Problem statement:
Given a string representing an expression of fraction addition and subtraction, you need to return the calculation result in string format. The final result should be irreducible fraction. If your final result is an integer, say 2
, you need to change it to the format of fraction that has denominator 1
. So in this case, 2
should be converted to 2/1
.
Example 1:
Input:"-1/2+1/2" Output: "0/1"
Example 2:
Input:"-1/2+1/2+1/3" Output: "1/3"
Example 3:
Input:"1/3-1/2" Output: "-1/6"
Example 4:
Input:"5/3+1/3" Output: "2/1"
Note:
- The input string only contains
'0'
to'9'
,'/'
,'+'
and'-'
. So does the output. - Each fraction (input and output) has format
±numerator/denominator
. If the first input fraction or the output is positive, then'+'
will be omitted. - The input only contains valid irreducible fractions, where the numerator and denominator of each fraction will always be in the range [1,10]. If the denominator is 1, it means this fraction is actually an integer in a fraction format defined above.
- The number of given fractions will be in the range [1,10].
- The numerator and denominator of the final result are guaranteed to be valid and in the range of 32-bit int.
Solution one: DFS from back to front(AC)
The input is an expression in the format of string. We need to divide the entire problem into small size. By the rules of addition associative law, we can not loop from front to back since the sign need to reverse if it is negative. So, looping from back to front is a good idea.
DFS model:
In this problem, I choose the DFS template with a return value(string).
In each level, I get a string representing a fraction, add it with the return value from the lower level and return the sum(string) to upper level.
In order to get the string fraction in current level, I stop at '+', '-' or the beginning position of the string(this is only useful when the first number in the string is positive).
For the purpose of a readable code, there are two functions, one function adds two string fractions and returns a string, another gets the greatest common divisor of two positive integers and return a positive integer.
Some knowledge need to be remembered, these are all I met when I coded:
- sscanf function:int sscanf ( const char * s, const char * format, ...);
- this function inherits from C style, the first element is const char *.
- string::resize(): return value is void, it can not be passed into a function as a parameter.
- Greatest Common Divisor(GCD): in order to get the correct GCD, both inputs are positive.
Time complexity is O(n). n is the size of the input string.
class Solution { public: string fractionAddition(string expression) { if(expression.empty()){ return "0/1"; } string second; for(int i = expression.size() - 1; i >= 0; i--){ if(expression[i] == '+' || expression[i] == '-' || i == 0){ second = expression.substr(i); break; } } // resize the string expression.resize(expression.size() - second.size()); string first = fractionAddition(expression); return add(first, second); } private: string add(string first, string second){ if(first.empty()){ return second; } int fn = 0, fd = 0, sn = 0, sd = 0; // get the number from expression sscanf(first.c_str(), "%d/%d", &fn, &fd); sscanf(second.c_str(), "%d/%d", &sn, &sd); int numerator = fn * sd + fd * sn; int denominator = fd * sd; if(numerator == 0){ return "0/1"; } int gcd = get_gcd(abs(numerator), abs(denominator)); // all input must be position to get GCD return to_string(numerator/gcd) + "/" + to_string(denominator/gcd); } // get greatest common divisor // the two inputs should be positive int get_gcd(int a, int b){ while(a != b){ if(a > b){ a -= b; } else { b -= a; } } return a; } };
Solution two:
This solution is intuitive, extract all fractions including their sign from the expression and push them into a vector, add them together.
Time complexity is O(n).
class Solution { public: string fractionAddition(string expression) { vector<string> fractions; for(int i = 0, j = 1; j <= expression.size(); j++){ if(j == expression.size() || expression[j] == '+' || expression[j] == '-'){ fractions.push_back(expression.substr(i, j - i)); i = j; } } string addition("0/1"); for(auto fraction : fractions){ addition = get_addition(addition, fraction); } return addition; } private: string get_addition(string first, string second){ int fn = 0, fd = 0, sn = 0, sd = 0; // get the number from expression sscanf(first.c_str(), "%d/%d", &fn, &fd); sscanf(second.c_str(), "%d/%d", &sn, &sd); int numerator = fn * sd + fd * sn; int denominator = fd * sd; if(numerator == 0){ return "0/1"; } int gcd = get_gcd(abs(numerator), abs(denominator)); // all input must be position to get GCD return to_string(numerator/gcd) + "/" + to_string(denominator/gcd); } // get greatest common divisor // the two inputs should be positive int get_gcd(int a, int b){ while(a != b){ if(a > b){ a -= b; } else { b -= a; } } return a; } };