📜  给定N分数的总和以简化形式(1)

📅  最后修改于: 2023-12-03 15:11:39.223000             🧑  作者: Mango

题目介绍

本题需要编写一个函数,输入为一个正整数 $N$ 和 $N$ 个分数,输出这 $N$ 个分数的总和,并对其进行简化表示。简化的分数仅保留最简分数形式,例如 $\frac{2}{4}$ 应该简化为 $\frac{1}{2}$。

函数签名

def simplify_fraction_sum(N: int, fractions: List[Tuple[int, int]]) -> Tuple[int, int]:
    pass
输入格式
  • N:正整数,表示分数的个数。
  • fractions:一个长度为 $N$ 的列表,每个元素都是一个长度为 2 的元组,表示一个分数,第一个元素为分子,第二个元素为分母。分子和分母都是正整数。
输出格式

一个元组,表示 $N$ 个分数的总和的最简形式,第一个元素为分子,第二个元素为分母。输出不需要保证分子和分母均为正数,但是必须是最简形式。

示例

示例 1
assert simplify_fraction_sum(2, [(1, 2), (1, 3)]) == (5, 6)

这个例子相当于计算 $\frac{1}{2} + \frac{1}{3}$,结果为 $\frac{5}{6}$。

示例 2
assert simplify_fraction_sum(3, [(1, 2), (1, 3), (1, 4)]) == (19, 12)

这个例子相当于计算 $\frac{1}{2} + \frac{1}{3} + \frac{1}{4}$,结果为 $\frac{19}{12}$。

思路

首先计算分数的和,找到它们的公共分母,然后将所有分数的分子相加就得到了分数的和。计算公共分母的方法是将所有分母的最小公倍数(LCM)作为公共分母。

然后,对分数进行简化,即将分式的分子和分母都除以它们的最大公约数。最大公约数可以使用辗转相除法求得。

代码实现

from typing import List, Tuple


def gcd(a: int, b: int) -> int:
    while b:
        a, b = b, a % b
    return a


def lcm(a: int, b: int) -> int:
    return a * b // gcd(a, b)


def simplify_fraction_sum(N: int, fractions: List[Tuple[int, int]]) -> Tuple[int, int]:
    common_denominator = 1
    for _, denominator in fractions:
        common_denominator = lcm(common_denominator, denominator)

    numerator_sum = 0
    for numerator, denominator in fractions:
        numerator_sum += numerator * (common_denominator // denominator)

    divisor = gcd(numerator_sum, common_denominator)
    return numerator_sum // divisor, common_denominator // divisor

复杂度分析

本算法主要包含两步操作。首先需要找到所有分母的 LCM,需要遍历所有分母,时间复杂度为 $O(n)$;然后需要对所有分子进行求和,时间复杂度也为 $O(n)$。因此总时间复杂度为 $O(n)$,与输入规模线性相关。

最坏情况下,分子和分母的取值可能达到输入值的较大倍数,导致计算 LCM 和 GCD 的时间复杂度增加,但是这种情况的概率较小。本算法优化的空间主要在合理识别这种情况,避免无谓的计算。