LeetCodee

592. Fraction Addition and Subtraction

Jump to Solution: Python Java C++ JavaScript C#

Problem Description

Given a string expression representing an expression of fraction addition and subtraction, return the calculation result in string format.

The final result should be an irreducible fraction. If your final result is an integer, change it to the format of a fraction that has a denominator 1. So in this case, 2 should be converted to 2/1.

Example 1:

Input: expression = "-1/2+1/2"
Output: "0/1"

Example 2:

Input: expression = "-1/2+1/2+1/3"
Output: "1/3"

Example 3:

Input: expression = "1/3-1/2"
Output: "-1/6"

Constraints:

  • The input string only contains '0' to '9', '/', '+' and '-'. So does the output.
  • Each fraction (input and output) has the 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

Python Solution

class Solution:
    def fractionAddition(self, expression: str) -> str:
        def gcd(a: int, b: int) -> int:
            return gcd(b, a % b) if b else abs(a)
        
        def lcm(a: int, b: int) -> int:
            return abs(a * b) // gcd(a, b)
        
        if expression[0] != '-':
            expression = '+' + expression
            
        nums = []
        dens = []
        i = 0
        while i < len(expression):
            sign = 1 if expression[i] == '+' else -1
            i += 1
            j = i
            while j < len(expression) and expression[j] != '/':
                j += 1
            num = int(expression[i:j]) * sign
            i = j + 1
            j = i
            while j < len(expression) and expression[j] not in '+-':
                j += 1
            den = int(expression[i:j])
            nums.append(num)
            dens.append(den)
            i = j
            
        lcm_den = dens[0]
        for i in range(1, len(dens)):
            lcm_den = lcm(lcm_den, dens[i])
            
        num_sum = 0
        for i in range(len(nums)):
            num_sum += nums[i] * (lcm_den // dens[i])
            
        if num_sum == 0:
            return "0/1"
            
        g = gcd(num_sum, lcm_den)
        return f"{num_sum // g}/{lcm_den // g}"

Time Complexity: O(n)

Where n is the length of the expression string.

Space Complexity: O(n)

For storing the numerators and denominators.

Java Solution

class Solution {
    private int gcd(int a, int b) {
        return b == 0 ? Math.abs(a) : gcd(b, a % b);
    }
    
    private int lcm(int a, int b) {
        return Math.abs(a * b) / gcd(a, b);
    }
    
    public String fractionAddition(String expression) {
        if (expression.charAt(0) != '-') {
            expression = "+" + expression;
        }
        
        List nums = new ArrayList<>();
        List dens = new ArrayList<>();
        int i = 0;
        while (i < expression.length()) {
            int sign = expression.charAt(i) == '+' ? 1 : -1;
            i++;
            int j = i;
            while (j < expression.length() && expression.charAt(j) != '/') {
                j++;
            }
            int num = Integer.parseInt(expression.substring(i, j)) * sign;
            i = j + 1;
            j = i;
            while (j < expression.length() && !isOperator(expression.charAt(j))) {
                j++;
            }
            int den = Integer.parseInt(expression.substring(i, j));
            nums.add(num);
            dens.add(den);
            i = j;
        }
        
        int lcmDen = dens.get(0);
        for (int k = 1; k < dens.size(); k++) {
            lcmDen = lcm(lcmDen, dens.get(k));
        }
        
        int numSum = 0;
        for (int k = 0; k < nums.size(); k++) {
            numSum += nums.get(k) * (lcmDen / dens.get(k));
        }
        
        if (numSum == 0) {
            return "0/1";
        }
        
        int g = gcd(numSum, lcmDen);
        return (numSum / g) + "/" + (lcmDen / g);
    }
    
    private boolean isOperator(char c) {
        return c == '+' || c == '-';
    }
}

Time Complexity: O(n)

Where n is the length of the expression string.

Space Complexity: O(n)

For storing the numerators and denominators.

C++ Solution

class Solution {
private:
    int gcd(int a, int b) {
        return b == 0 ? abs(a) : gcd(b, a % b);
    }
    
    int lcm(int a, int b) {
        return abs(a * b) / gcd(a, b);
    }
    
public:
    string fractionAddition(string expression) {
        if (expression[0] != '-') {
            expression = "+" + expression;
        }
        
        vector nums;
        vector dens;
        int i = 0;
        while (i < expression.length()) {
            int sign = expression[i] == '+' ? 1 : -1;
            i++;
            int j = i;
            while (j < expression.length() && expression[j] != '/') {
                j++;
            }
            int num = stoi(expression.substr(i, j - i)) * sign;
            i = j + 1;
            j = i;
            while (j < expression.length() && expression[j] != '+' && expression[j] != '-') {
                j++;
            }
            int den = stoi(expression.substr(i, j - i));
            nums.push_back(num);
            dens.push_back(den);
            i = j;
        }
        
        int lcm_den = dens[0];
        for (int k = 1; k < dens.size(); k++) {
            lcm_den = lcm(lcm_den, dens[k]);
        }
        
        int num_sum = 0;
        for (int k = 0; k < nums.size(); k++) {
            num_sum += nums[k] * (lcm_den / dens[k]);
        }
        
        if (num_sum == 0) {
            return "0/1";
        }
        
        int g = gcd(num_sum, lcm_den);
        return to_string(num_sum / g) + "/" + to_string(lcm_den / g);
    }
};

Time Complexity: O(n)

Where n is the length of the expression string.

Space Complexity: O(n)

For storing the numerators and denominators.

JavaScript Solution

/**
 * @param {string} expression
 * @return {string}
 */
var fractionAddition = function(expression) {
    const gcd = (a, b) => b === 0 ? Math.abs(a) : gcd(b, a % b);
    const lcm = (a, b) => Math.abs(a * b) / gcd(a, b);
    
    if (expression[0] !== '-') {
        expression = '+' + expression;
    }
    
    const nums = [];
    const dens = [];
    let i = 0;
    while (i < expression.length) {
        const sign = expression[i] === '+' ? 1 : -1;
        i++;
        let j = i;
        while (j < expression.length && expression[j] !== '/') {
            j++;
        }
        const num = parseInt(expression.slice(i, j)) * sign;
        i = j + 1;
        j = i;
        while (j < expression.length && expression[j] !== '+' && expression[j] !== '-') {
            j++;
        }
        const den = parseInt(expression.slice(i, j));
        nums.push(num);
        dens.push(den);
        i = j;
    }
    
    let lcmDen = dens[0];
    for (let k = 1; k < dens.length; k++) {
        lcmDen = lcm(lcmDen, dens[k]);
    }
    
    let numSum = 0;
    for (let k = 0; k < nums.length; k++) {
        numSum += nums[k] * (lcmDen / dens[k]);
    }
    
    if (numSum === 0) {
        return "0/1";
    }
    
    const g = gcd(numSum, lcmDen);
    return `${numSum / g}/${lcmDen / g}`;
};

Time Complexity: O(n)

Where n is the length of the expression string.

Space Complexity: O(n)

For storing the numerators and denominators.

C# Solution

public class Solution {
    private int Gcd(int a, int b) {
        return b == 0 ? Math.Abs(a) : Gcd(b, a % b);
    }
    
    private int Lcm(int a, int b) {
        return Math.Abs(a * b) / Gcd(a, b);
    }
    
    public string FractionAddition(string expression) {
        if (expression[0] != '-') {
            expression = "+" + expression;
        }
        
        var nums = new List();
        var dens = new List();
        int i = 0;
        while (i < expression.Length) {
            int sign = expression[i] == '+' ? 1 : -1;
            i++;
            int j = i;
            while (j < expression.Length && expression[j] != '/') {
                j++;
            }
            int num = int.Parse(expression.Substring(i, j - i)) * sign;
            i = j + 1;
            j = i;
            while (j < expression.Length && expression[j] != '+' && expression[j] != '-') {
                j++;
            }
            int den = int.Parse(expression.Substring(i, j - i));
            nums.Add(num);
            dens.Add(den);
            i = j;
        }
        
        int lcmDen = dens[0];
        for (int k = 1; k < dens.Count; k++) {
            lcmDen = Lcm(lcmDen, dens[k]);
        }
        
        int numSum = 0;
        for (int k = 0; k < nums.Count; k++) {
            numSum += nums[k] * (lcmDen / dens[k]);
        }
        
        if (numSum == 0) {
            return "0/1";
        }
        
        int g = Gcd(numSum, lcmDen);
        return $"{numSum / g}/{lcmDen / g}";
    }
}

Time Complexity: O(n)

Where n is the length of the expression string.

Space Complexity: O(n)

For storing the numerators and denominators.

Approach Explanation

The solution uses fraction arithmetic and string parsing:

  1. Key Insights:
    • Fraction arithmetic
    • GCD and LCM
    • String parsing
    • Fraction reduction
  2. Algorithm Steps:
    • Parse fractions
    • Find common denominator
    • Add numerators
    • Reduce result

Implementation Details:

  • String manipulation
  • Number parsing
  • Fraction operations
  • Result formatting

Optimization Insights:

  • Early return
  • Efficient GCD
  • Memory usage
  • String operations

Edge Cases:

  • Zero result
  • Negative fractions
  • Single fraction
  • Integer result