原文链接: https://leetcode-cn.com/problems/equal-rational-numbers
英文原文
Given two strings s
and t
, each of which represents a non-negative rational number, return true
if and only if they represent the same number. The strings may use parentheses to denote the repeating part of the rational number.
A rational number can be represented using up to three parts: <IntegerPart>
, <NonRepeatingPart>
, and a <RepeatingPart>
. The number will be represented in one of the following three ways:
<IntegerPart>
<ul> <li>For example, <code>12</code>, <code>0</code>, and <code>123</code>.</li> </ul> </li> <li><code><IntegerPart><strong><.></strong><NonRepeatingPart></code> <ul> <li>For example, <code>0.5</code>, <code>1.</code>, <code>2.12</code>, and <code>123.0001</code>.</li> </ul> </li> <li><code><IntegerPart><strong><.></strong><NonRepeatingPart><strong><(></strong><RepeatingPart><strong><)></strong></code> <ul> <li>For example, <code>0.1(6)</code>, <code>1.(9)</code>, <code>123.00(1212)</code>.</li> </ul> </li>
The repeating portion of a decimal expansion is conventionally denoted within a pair of round brackets. For example:
1/6 = 0.16666666... = 0.1(6) = 0.1666(6) = 0.166(66)
.
Example 1:
Input: s = "0.(52)", t = "0.5(25)" Output: true Explanation: Because "0.(52)" represents 0.52525252..., and "0.5(25)" represents 0.52525252525..... , the strings represent the same number.
Example 2:
Input: s = "0.1666(6)", t = "0.166(66)" Output: true
Example 3:
Input: s = "0.9(9)", t = "1." Output: true Explanation: "0.9(9)" represents 0.999999999... repeated forever, which equals 1. [See this link for an explanation.] "1." represents the number 1, which is formed correctly: (IntegerPart) = "1" and (NonRepeatingPart) = "".
Constraints:
- Each part consists only of digits.
- The
<IntegerPart>
does not have leading zeros (except for the zero itself). 1 <= <IntegerPart>.length <= 4
0 <= <NonRepeatingPart>.length <= 4
1 <= <RepeatingPart>.length <= 4
中文题目
给定两个字符串 S
和 T
,每个字符串代表一个非负有理数,只有当它们表示相同的数字时才返回 true;否则,返回 false。字符串中可以使用括号来表示有理数的重复部分。
通常,有理数最多可以用三个部分来表示:整数部分 <IntegerPart>
、小数非重复部分 <NonRepeatingPart>
和小数重复部分 <(><RepeatingPart><)>
。数字可以用以下三种方法之一来表示:
<IntegerPart>
(例:0,12,123)<IntegerPart><.><NonRepeatingPart>
(例:0.5,2.12,2.0001)<IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)>
(例:0.1(6),0.9(9),0.00(1212))
十进制展开的重复部分通常在一对圆括号内表示。例如:
1 / 6 = 0.16666666... = 0.1(6) = 0.1666(6) = 0.166(66)
0.1(6) 或 0.1666(6) 或 0.166(66) 都是 1 / 6 的正确表示形式。
示例 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 。[有关说明,请参阅此链接] "1." 表示数字 1,其格式正确:(IntegerPart) = "1" 且 (NonRepeatingPart) = "" 。
提示:
- 每个部分仅由数字组成。
- 整数部分
<IntegerPart>
不会以 2 个或更多的零开头。(对每个部分的数字没有其他限制)。 1 <= <IntegerPart>.length <= 4
0 <= <NonRepeatingPart>.length <= 4
1 <= <RepeatingPart>.length <= 4
通过代码
官方题解
方法:分数类
思路
因为给定的两个数字都表示一个分数,所以我们需要一个分数类去处理这两个分数。它应该能帮助我们将两个分数加起来,并且保证答案为最简形式。
算法
我们需要理解给定的两个分数,最困难的问题是如何表示它们。
比如说我们有一个字符串 S = "0.(12)"
。它代表(定义 $r = \frac{1}{100}$):
$$
S = \frac{12}{100} + \frac{12}{10000} + \frac{12}{10^6} + \frac{12}{10^8} + \frac{12}{10^{10}} + \cdots
$$
$$
S = 12 * (r + r^2 + r^3 + \cdots)
$$
$$
S = 12 * \frac{r}{1-r}
$$
其中 $(r + r^2 + r^3 + \cdots)$ 是一个等比数列求和问题。
总而言之,对于长度为 $k$ 的重复部分 $x$,会对答案有 $\frac{xr}{1-r}$ 的贡献,其中 $r = 10^{-k}$。
另外两部分就更容易计算了,因为它们仅仅是对数值的简单翻译。
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;
}
}
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)$。
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
1338 | 3297 | 40.6% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|