leetcode
leetcode 501 ~ 550
分数加减运算

分数加减运算

难度:

标签:

题目描述

代码结果

运行时间: 28 ms, 内存: 16.1 MB


/*
 思路:
 1. 解析输入字符串,将每个分数解析出来。
 2. 使用Java Stream进行分数加法计算。
 3. 计算结果的分子和分母,并将结果转换为最简分数。
 4. 如果结果为整数,则将其转换为分数形式(分母为1)。
 */
import java.util.*;
import java.util.stream.*;
 
public class FractionAdditionStream {
    public String fractionAddition(String expression) {
        List<int[]> fractions = new ArrayList<>();
        int index = 0, n = expression.length();
        while (index < n) {
            int sign = 1;
            if (expression.charAt(index) == '-') {
                sign = -1;
                index++;
            } else if (expression.charAt(index) == '+') {
                index++;
            }
            int numerator = 0;
            while (index < n && Character.isDigit(expression.charAt(index))) {
                numerator = numerator * 10 + (expression.charAt(index) - '0');
                index++;
            }
            numerator *= sign;
            index++; // skip '/'
            int denominator = 0;
            while (index < n && Character.isDigit(expression.charAt(index))) {
                denominator = denominator * 10 + (expression.charAt(index) - '0');
                index++;
            }
            fractions.add(new int[]{numerator, denominator});
        }
        int[] result = fractions.stream()
                .reduce(new int[]{0, 1}, (a, b) -> addFractions(a[0], a[1], b[0], b[1]));
        return result[0] + "/" + result[1];
    }
 
    private int[] addFractions(int num1, int denom1, int num2, int denom2) {
        int lcm = lcm(denom1, denom2);
        int numerator = num1 * (lcm / denom1) + num2 * (lcm / denom2);
        int gcd = gcd(Math.abs(numerator), lcm);
        return new int[]{numerator / gcd, lcm / gcd};
    }
 
    private int lcm(int a, int b) {
        return a * (b / gcd(a, b));
    }
 
    private int gcd(int a, int b) {
        while (b != 0) {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
}
 

解释

方法:

这个题解的思路是模拟分数加减运算的过程。首先定义了求最大公约数(gcd)和最小公倍数(lcm)的函数。然后定义了分数加法函数add,根据两个分数的分母是否相同来进行不同的处理。接着遍历给定的表达式,用一个临时变量 tmp 来记录当前处理的数字。遇到 '+' 或 '-' 时,根据前面的符号对当前分数进行加减运算,并更新符号。遇到 '/' 时,将当前数字作为分子,并切换到分母。最后,将表达式中最后一个分数也加入计算,并对结果进行约分。

时间复杂度:

O(nlogM),其中 n 是表达式的长度,M 是分母的最大值。

空间复杂度:

O(1)

代码细节讲解

🦆
在处理分数时,为什么选择使用列表`[numerator, denominator]`表示分数,而不是创建一个分数类或使用其他数据结构?
在LeetCode等在线编程平台上编写解题代码时,通常优先选择简单和直观的解决方案以减少代码复杂度和提高执行效率。使用列表`[numerator, denominator]`直接表示分数是一种简单有效的方式,可以快速访问和修改分子和分母。此外,使用Python列表比创建一个自定义的分数类要少写更多的代码,并且在没有提供分数操作的内置库支持的情况下,使用列表可以更容易地进行分数的基本操作,如加减和乘除。
🦆
在解析表达式并构建分数时,代码是如何确保每次遇到运算符时正确处理之前的数字和运算符的?
代码通过维护一个临时字符串`tmp`来收集当前数字,并使用`sign`变量来记录最近的运算符(+或-)。每次遇到新的运算符或表达式结束时,代码会将`tmp`中的内容转换为整数并更新到当前处理的分数`num`中,然后根据`sign`将这个分数与之前的结果`res`进行加减运算。这种方法确保了每次遇到运算符时都能将之前的分数正确地加入到总结果中,然后重置`tmp`和更新`sign`以准备下一个分数的处理。
🦆
函数`add`在处理不同分母的分数时使用了最小公倍数(lcm)。这个方法是否总是有效,即是否有可能导致整数溢出或在某些编程语言中处理大数字时遇到性能瓶颈?
使用最小公倍数(lcm)来处理不同分母的分数确实是一个有效的方法,因为它允许两个分数在相同的分母下进行加减运算。然而,这种方法可能会导致整数溢出,特别是当分母非常大时。在Python中,整数类型可以自动处理大数,但在其他一些语言中,如C++或Java,大数可能导致性能瓶颈或需要使用特定的库来处理大整数。因此,虽然这种方法在Python中通常是安全的,但在其他语言中可能需要额外的注意和处理。
🦆
在代码中,如何处理表达式开头是负号的情况,比如`-1/2+1/2`,是如何初始化`sign`和`num`以确保第一个分数正确解析的?
在代码中,`sign`变量默认初始化为1。当解析表达式时,如果表达式的第一个字符是负号`-`,则在遇到这个负号时将`sign`设置为-1。这样,当读取到第一个分数的数字时,它会根据这个`sign`被正确地解析为负数。这种处理确保了即使表达式以负号开始,第一个分数也能被正确地解析和处理。

相关问题

求解方程

求解一个给定的方程,将x以字符串 "x=#value" 的形式返回。该方程仅包含 '+''-' 操作,变量 x 和其对应系数。

如果方程没有解或存在的解不为整数,请返回 "No solution" 。如果方程有无限解,则返回 “Infinite solutions”

题目保证,如果方程中只有一个解,则 'x' 的值是一个整数。

 

示例 1:

输入: equation = "x+5-3+x=6+x-2"
输出: "x=2"

示例 2:

输入: equation = "x=x"
输出: "Infinite solutions"

示例 3:

输入: equation = "2x=x"
输出: "x=0"

 

提示:

  • 3 <= equation.length <= 1000
  • equation 只有一个 '='
  • 方程由绝对值在 [0, 100]  范围内且无任何前导零的整数和变量 'x' 组成。​​​