0972-相等的有理数

Raphael Liu Lv10

给定两个字符串 st ,每个字符串代表一个非负有理数,只有当它们表示相同的数字时才返回 true
。字符串中可以使用括号来表示有理数的重复部分。

有理数 最多可以用三个部分来表示: 整数部分 <IntegerPart>小数非重复部分
<NonRepeatingPart>小数重复部分 <(><RepeatingPart><)>。数字可以用以下三种方法之一来表示:

  • <IntegerPart>
    • 例: 0 ,12123
  • <IntegerPart><.><NonRepeatingPart>
    • 例: 0.5 , ``1. , 2.12123.0001
  • <IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)>
    • 例: 0.1(6)1.(9)123.00(1212)

十进制展开的重复部分通常在一对圆括号内表示。例如:

  • 1 / 6 = 0.16666666... = 0.1(6) = 0.1666(6) = 0.166(66)

示例 1:

**输入:** s = "0.(52)", t = "0.5(25)"
**输出:** true
**解释:** 因为 "0.(52)" 代表 0.52525252...,而 "0.5(25)" 代表 0.52525252525.....,则这两个字符串表示相同的数字。

示例 2:

**输入:** s = "0.1666(6)", t = "0.166(66)"
**输出:** true

示例 3:

**输入:** s = "0.9(9)", t = "1."
**输出:** true
**解释:** "0.9(9)" 代表 0.999999999... 永远重复,等于 1 。[[有关说明,请参阅此链接](https://baike.baidu.com/item/0.999…/5615429?fr=aladdin)]
"1." 表示数字 1,其格式正确:(IntegerPart) = "1" 且 (NonRepeatingPart) = "" 。

提示:

  • 每个部分仅由数字组成。
  • 整数部分 <IntegerPart> 不会以零开头。(零本身除外)
  • 1 <= <IntegerPart>.length <= 4
  • 0 <= <NonRepeatingPart>.length <= 4
  • 1 <= <RepeatingPart>.length <= 4

​​​​​

方法:分数类

思路

因为给定的两个数字都表示一个分数,所以我们需要一个分数类去处理这两个分数。它应该能帮助我们将两个分数加起来,并且保证答案为最简形式。

算法

我们需要理解给定的两个分数,最困难的问题是如何表示它们。

比如说我们有一个字符串 S = "0.(12)"。它代表(定义 r = 1/100):

S = 12/100} + 12/10000} + 12/10^6} + 12/10^8} + 12/10^{10}} + \cdots

S = 12 * (r + r^2 + r^3 + \cdots)

S = 12 * r}{1-r}

其中 (r + r^2 + r^3 + \cdots) 是一个等比数列求和问题。

总而言之,对于长度为 k 的重复部分 x,会对答案有 xr}{1-r 的贡献,其中 r = 10^{-k。

另外两部分就更容易计算了,因为它们仅仅是对数值的简单翻译。

[QFRcSJ8K-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Solution {
public boolean isRationalEqual(String S, String T) {
Fraction f1 = convert(S);
Fraction f2 = convert(T);
return f1.n == f2.n && f1.d == f2.d;
}

public Fraction convert(String S) {
int state = 0; //whole, decimal, repeating
Fraction ans = new Fraction(0, 1);
int decimal_size = 0;

for (String part: S.split("[.()]")) {
state++;
if (part.isEmpty()) continue;
long x = Long.valueOf(part);
int sz = part.length();

if (state == 1) { // whole
ans.iadd(new Fraction(x, 1));
} else if (state == 2) { // decimal
ans.iadd(new Fraction(x, (long) Math.pow(10, sz)));
decimal_size = sz;
} else { // repeating
long denom = (long) Math.pow(10, decimal_size);
denom *= (long) (Math.pow(10, sz) - 1);
ans.iadd(new Fraction(x, denom));
}
}
return ans;
}
}

class Fraction {
long n, d;
Fraction(long n, long d) {
long g = gcd(n, d);
this.n = n / g;
this.d = d / g;
}

public void iadd(Fraction other) {
long numerator = this.n * other.d + this.d * other.n;
long denominator = this.d * other.d;
long g = Fraction.gcd(numerator, denominator);
this.n = numerator / g;
this.d = denominator / g;
}

static long gcd(long x, long y) {
return x != 0 ? gcd(y % x, x) : y;
}
}
[QFRcSJ8K-Python]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from fractions import Fraction

class Solution(object):
def isRationalEqual(self, S, T):
def convert(S):
if '.' not in S:
return Fraction(int(S), 1)
i = S.index('.')
ans = Fraction(int(S[:i]), 1)
S = S[i+1:]
if '(' not in S:
if S:
ans += Fraction(int(S), 10 ** len(S))
return ans

i = S.index('(')
if i:
ans += Fraction(int(S[:i]), 10 ** i)
S = S[i+1:-1]
j = len(S)
ans += Fraction(int(S), 10**i * (10**j - 1))
return ans

return convert(S) == convert(T)

复杂度分析

  • 时间复杂度:O(1),因为字符串 S, T 的长度可以看作是 O(1) 级别的。

  • 空间复杂度:O(1)。

 Comments
On this page
0972-相等的有理数