I'm currently trying to design an algorithm that doing such thing:
I got two strings A and B which consist of lowercase characters 'a'-'z'
and I can modify string A using the following operations:
1. Select two characters 'c1' and 'c2' from the character set ['a'-'z'].
2. Replace all characters 'c1' in string A with character 'c2'.
I need to find the minimum number of operations needed to convert string A to string B when possible.
I have 2 ideas that didn't work
1. Simple range-based for cycle that changes string B and compares it with A.
2. Idea with map<char, int> that does the same.
Right now I'm stuck on unit-testing with such situation : 'ab' is transferable to 'ba' in 3 iterations and 'abc' to 'bca' in 4 iterations.
My algorithm is wrong and I need some fresh ideas or working solution.
Can anyone help with this?
Here is some code that shows minimal RepEx:
int Transform(string& A, string& B)
{
int count = 0;
if(A.size() != B.size()){
return -1;
}
for(int i = A.size() - 1; i >= 0; i--){
if(A[i]!=B[i]){
char rep_elem = A[i];
++count;
replace(A.begin(),A.end(),rep_elem,B[i]);
}
}
if(A != B){
return -1;
}
return count;
}
How can I improve this or I should find another ideas?
First of all, don't worry about string operations. Your problem is algorithmic, not textual. You should somehow analyze your data, and only afterwards print your solution.
Start with building a data structure which tells, for each letter, which letter it should be replaced with. Use an array (or std::map<char, char> — it should conceptually be similar, but have different syntax).
If you discover that you should convert a letter to two different letters — error, conversion impossible. Otherwise, count the number of non-trivial cycles in the conversion graph.
The length of your solution will be the number of letters which shouldn't be replaced by themselves plus the number of cycles.
I think the code to implement this would be too long to be helpful.
Related
I am trying to convert strings to integers and sort them based on the integer value. These values should be unique to the string, no other string should be able to produce the same value. And if a string1 is bigger than string2, its integer value should be greater. Ex: since "orange" > "apple", "orange" should have a greater integer value. How can I do this?
I know there are an infinite number of possibilities between just 'a' and 'b' but I am not trying to fit every single possibility into a number. I am just trying to possibly sort, let say 1 million values, not an infinite amount.
I was able to get the values to be unique using the following:
long int order = 0;
for (auto letter : word)
order = order * 26 + letter - 'a' + 1;
return order;
but this obviously does not work since the value for "apple" will be greater than the value for "z".
This is not a homework assignment or a puzzle, this is something I thought of myself. Your help is appreciated, thank you!
You are almost there ... just a minor tweaks are needed:
you are multiplying by 26
however you have letters (a..z) and empty space so you should multiply by 27 instead !!!
Add zeropading
in order to make starting letter the most significant digit you should zeropad/align the strings to common length... if you are using 32bit integers then max size of string is:
floor(log27(2^32)) = 6
floor(32/log2(27)) = 6
Here small example:
int lexhash(char *s)
{
int i,h;
for (h=0,i=0;i<6;i++) // process string
{
if (s[i]==0) break;
h*=27;
h+=s[i]-'a'+1;
}
for (;i<6;i++) h*=27; // zeropad missing letters
return h;
}
returning these:
14348907 a
28697814 b
43046721 c
373071582 z
15470838 abc
358171551 xyz
23175774 apple
224829626 orange
ordered by hash:
14348907 a
15470838 abc
23175774 apple
28697814 b
43046721 c
224829626 orange
358171551 xyz
373071582 z
This will handle all lowercase a..z strings up to 6 characters length which is:
26^6 + 26^5 +26^4 + 26^3 + 26^2 + 26^1 = 321272406 possibilities
For more just use bigger bitwidth for the hash. Do not forget to use unsigned type if you use the highest bit of it too (not the case for 32bit)
You can use position of char:
std::string s("apple");
int result = 0;
for (size_t i = 0; i < s.size(); ++i)
result += (s[i] - 'a') * static_cast<int>(i + 1);
return result;
By the way, you are trying to get something very similar to hash function.
I'm trying to alphabetize words in a vector of strings and my program is distinguishing between upper and lowercase letters, so uppercase words always appear first in the sorted list. I can think of potentially really cumbersome ways to make sure the upper case words go in their place, but is there a simple way to do this?
Here is my code:
for (int i = 0; i < str.size(); i++)
{
for (int j = 0; j < str.size(); j++)
{
if (str.at(i) > str.at(j))
{
temp = str.at(j);
str.at(j) = str.at(i);
str.at(i) = temp;
}
}
}
Also, this is for a programming assignment, so I am not allowed to use built in C++ functions to do this and I have to use a vector.
The trick to solving this is to write a replacement for this line
if (str.at(i) > str.at(j))
that performs case-insensitive comparison. Start by writing a signature for it:
bool greaterThanIgnoreCase(const string& left, const string& right) {
...
}
Now you can replace your if condition with a call to this new function:
if (greaterThanIgnoreCase(str.at(i), str.at(j)))
Finally, you need to provide an implementation of greaterThanIgnoreCase function. This is the core of the problem, so you would need to do it yourself. The trick to it is using toupper or tolower function on each character of strings left and right, and compare them one character at a time. If you run out of characters in one of the strings, the one with some characters remaining should be considered greater.
The only thing you need to do is to compare lowercased characters. If you are not allowed to use any built-in functions, you can do it manually.
Since lowercase characters are located in ASCII table starting from 97, and uppercase - starting from 65, you can simply add 32 to the uppercase char to get its lowercase equivalent.
char lowerCase(char c)
{
if (c >= 'A' && c <= 'Z') // if char is uppercase
return (char)(c + 32); // return its lowercase equivalent
else
return c;
}
Then, you can do the following in your if condition:
if (lowerCase(str.at(i)) > lowerCase(str.at(j)))
Note that you shouldn use lowerCase only when you compare, but not when you assign.
Here is the working IDEOne demo.
If you have a vector of strings then you could/should use the STL library, which offers sort or stable_sort for a given comparison function (that can be a simple lambda expression, functor, function,...).
Update: You're not allowed to use built-in types except vector.
In this case you can develop easily a replicate of what STL does.
Define a sort function that receives a comparator (for a vector of strings).
I'm working on an assignment where we have to create a "MyInt" class that can handle larger numbers than regular ints. We only have to handle non-negative numbers. I need to overload the >> operator for this class, but I'm struggling to do that.
I'm not allowed to #include <string>.
Is there a way to:
a. Accept input as a C-style string
b. Parse through it and check for white space and non-numbers (i.e. if the prompt is cin >> x >> y >> ch, and the user enters 1000 934H, to accept that input as two MyInts and then a char).
I'm assuming it has something to do with peek() and get(), but I'm having trouble figuring out where they come in.
I'd rather not know exactly how to do it! Just point me in the right direction.
Here's my constructor, so you can get an idea for what the class is (I also have a conversion constructor for const char *.
MyInt::MyInt (int n)
{
maxsize = 1;
for (int i = n; i > 9; i /= 10) {
// Divides the number by 10 to find the number of times it is divisible; that is the length
maxsize++;
}
intstring = new int[maxsize];
for (int j = (maxsize - 1); j >= 0; j--) {
// Copies the integer into an integer array by use of the modulus operator
intstring[j] = n % 10;
n = n / 10;
}
}
Thanks! Sorry if this question is vague, I'm still new to this. Let me know if I can provide any more info to make the question clearer.
So what you basically want is to parse a const char* to retrieve a integer number inside it, and ignore all whitespace(+others?) characters.
Remember that characters like '1' or 'M' or even ' ' are just integers, mapped to the ASCII table. So you can easily convert a character from its notation human-readable ('a') to its value in memory. There are plenty of sources on ascii table and chars in C/C++ so i'll let you find it, but you should get the idea. In C/C++, characters are numbers (of type char).
With this, you then know you can perform operations on them, like addition, or comparison.
Last thing when dealing with C-strings : they are null-terminated, meaning that the character '\0' is placed right after their last used character.
I'm writing a program that will balance Chemistry Equations; I thought it'd be a good challenge and help reinforce the information I've recently learned.
My program is set up to use getline(cin, std::string) to receive the equation. From there it separates the equation into two halves: a left side and right side by making a substring when it encounters a =.
I'm having issues which only concerns the left side of my string, which is called std::string leftSide. My program then goes into a for loop that iterates over the length of leftSide. The first condition checks to see if the character is uppercase, because chemical formulas are written with the element symbols and a symbol consists of either one upper case letter, or an upper case and one lower case letter. After it checks to see if the current character is uppercase, it checks to see if the next character is lower case; if it's lower case then I create a temporary string, combine leftSide[index] with leftSide[index+1] in the temp string then push the string to my vector.
My problem lies on the first iteration; I've been using CuFe3 = 8 (right side doesn't matter right now) to test it out. The only thing stored in std::string temp is C. I'm not sure why this happening; also, I'm still getting numbers in my final answer and I don't understand why. Some help fixing these two issues, along with an explanation, would be greatly appreciated.
[CODE]
int index = 0;
for (it = leftSide.begin(); it!=leftSide.end(); ++it, index++)
{
bool UPPER_LETTER = isupper(leftSide[index]);
bool NEXT_LOWER_LETTER = islower(leftSide[index+1]);
if (UPPER_LETTER)// if the character is an uppercase letter
{
if (NEXT_LOWER_LETTER)
{
string temp = leftSide.substr(index, (index+1));//add THIS capital and next lowercase
elementSymbol.push_back(temp); // add temp to vector
temp.clear(); //used to try and fix problem initially
}
else if (UPPER_LETTER && !NEXT_LOWER_LETTER) //used to try and prevent number from getting in
{
string temp = leftSide.substr(index, index);
elementSymbol.push_back(temp);
}
}
else if (isdigit(leftSide[index])) // if it's a number
num++;
}
[EDIT] When I entered in only ASDF, *** ***S ***DF ***F was the output.
string temp = leftSide.substr(index, (index+1));
substr takes the first index and then a length, rather than first and last indices. You want substr(index, 2). Since in your example index is 0 you're doing: substr(index, 1) which creates a string of length 1, which is "C".
string temp = leftSide.substr(index, index);
Since index is 0 this is substr(index, 0), which creates a string of length 0, that is, an empty string.
When you're processing parts of the string with a higher index, such as Fe in "CuFe3" the value you pass in as the length parameter is higher and so you're creating strings that are longer. F is at index 2 and you call substr(index, 3), which creates the string "Fe3".
Also the standard library usually uses half open ranges, so even if substr took two indices (which, again, it doesn't) you would do substr(index, index+2) to get a two character string.
bool NEXT_LOWER_LETTER = islower(leftSide[index+1]);
You might want to check that index+1 is a valid index. If you don't want to do that manually you might at least switch to using the bounds checked function at() instead of operator[].
All:
I got one question in string parsing:
For now, if I have a string like "+12+400-500+2:+13-50-510+20-66+20:"
How can I do like calculate total sum of each segment( : can be consider as end of one segment). For now, what I can figure out is only use for to loop through and check +/- sign, but I do not think it is good for a Universal method to solve this kind of problem :(
For example, the first segment, +12+400-500+2 = -86, and the second segment is
+13-50-510+20-66+20 = -573
1) The number of operand is varied( but they are always integer)
2) The number of segment is varied
3) I need do it in C++ or C.
I do not really think it as a very simple question to most newbie, and also I will claim this is not a homework. :)
best,
Since the string ends in a colon, it is easy to use find and substr to separate out parts of the string partitioned by ':', like this:
string all("+12+400-500+2:+13-50-510+20-66+20:");
int pos = 0;
for (;;) {
int next = all.find(':', pos);
if (next == string::npos) break;
string expr(all.substr(pos, (next-pos)+1));
cout << expr << endl;
pos = next+1;
}
This splits the original string into parts
+12+400-500+2:
and
+13-50-510+20-66+20:
Since istreams take leading plus as well as leading minus, you can parse out the numbers using >> operator:
istringstream iss(expr);
while (iss) {
int n;
iss >> n;
cout << n << endl;
}
With these two parts in hand, you can easily total up the individual numbers, and produce the desired output. Here is a quick demo.
You need to seperate operands and operators. To do this you can use two queue data types one for operands and one for operators
split by :, then by +, then by -. translate into int and there you are.
Your expression language seems regular: you could use a regex library - like boost::regex - to match the numbers, the signs, and the segments in groups directly, with something like
((([+-])([0-9]+))+)(:((([+-])([0-9]))+))+