Overflow in intermediate arithmetic
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
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>
12, 0, and 123.<IntegerPart><.><NonRepeatingPart>
0.5, 1., 2.12, and 123.0001.<IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)>
0.1(6), 1.(9), 123.00(1212).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:
<IntegerPart> does not have leading zeros (except for the zero itself).1 <= <IntegerPart>.length <= 40 <= <NonRepeatingPart>.length <= 41 <= <RepeatingPart>.length <= 4Problem summary: 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> For example, 12, 0, and 123. <IntegerPart><.><NonRepeatingPart> For example, 0.5, 1., 2.12, and 123.0001. <IntegerPart><.><NonRepeatingPart><(><RepeatingPart><)> For example, 0.1(6), 1.(9), 123.00(1212). 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).
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Math
"0.(52)" "0.5(25)"
"0.1666(6)" "0.166(66)"
"0.9(9)" "1."
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #972: Equal Rational Numbers
class Solution {
public boolean isRationalEqual(String s, String t) {
return Math.abs(valueOf(s) - valueOf(t)) < 1e-9;
}
private static double[] ratios = new double[] {1.0, 1.0 / 9, 1.0 / 99, 1.0 / 999, 1.0 / 9999};
private double valueOf(final String s) {
if (!s.contains("("))
return Double.valueOf(s);
// Get the indices..
final int leftParenIndex = s.indexOf('(');
final int rightParenIndex = s.indexOf(')');
final int dotIndex = s.indexOf('.');
// integerAndNonRepeating := <IntegerPart><.><NonRepeatingPart>
final double nonRepeating = Double.valueOf(s.substring(0, leftParenIndex));
final int nonRepeatingLength = leftParenIndex - dotIndex - 1;
// repeating := <RepeatingPart>
final int repeating = Integer.parseInt(s.substring(leftParenIndex + 1, rightParenIndex));
final int repeatingLength = rightParenIndex - leftParenIndex - 1;
return nonRepeating + repeating * Math.pow(0.1, nonRepeatingLength) * ratios[repeatingLength];
}
}
// Accepted solution for LeetCode #972: Equal Rational Numbers
// Auto-generated Go example from java.
func exampleSolution() {
}
// Reference (java):
// // Accepted solution for LeetCode #972: Equal Rational Numbers
// class Solution {
// public boolean isRationalEqual(String s, String t) {
// return Math.abs(valueOf(s) - valueOf(t)) < 1e-9;
// }
//
// private static double[] ratios = new double[] {1.0, 1.0 / 9, 1.0 / 99, 1.0 / 999, 1.0 / 9999};
//
// private double valueOf(final String s) {
// if (!s.contains("("))
// return Double.valueOf(s);
//
// // Get the indices..
// final int leftParenIndex = s.indexOf('(');
// final int rightParenIndex = s.indexOf(')');
// final int dotIndex = s.indexOf('.');
//
// // integerAndNonRepeating := <IntegerPart><.><NonRepeatingPart>
// final double nonRepeating = Double.valueOf(s.substring(0, leftParenIndex));
// final int nonRepeatingLength = leftParenIndex - dotIndex - 1;
//
// // repeating := <RepeatingPart>
// final int repeating = Integer.parseInt(s.substring(leftParenIndex + 1, rightParenIndex));
// final int repeatingLength = rightParenIndex - leftParenIndex - 1;
// return nonRepeating + repeating * Math.pow(0.1, nonRepeatingLength) * ratios[repeatingLength];
// }
// }
# Accepted solution for LeetCode #972: Equal Rational Numbers
class Solution:
def isRationalEqual(self, s: str, t: str) -> bool:
ratios = [1, 1 / 9, 1 / 99, 1 / 999, 1 / 9999]
def valueOf(s: str) -> float:
if s.find('(') == -1:
return float(s)
# Get the indices.
leftParenIndex = s.find('(')
rightParenIndex = s.find(')')
dotIndex = s.find('.')
# integerAndNonRepeating := <IntegerPart><.><NonRepeatingPart>
integerAndNonRepeating = float(s[:leftParenIndex])
nonRepeatingLength = leftParenIndex - dotIndex - 1
# repeating := <RepeatingPart>
repeating = int(s[leftParenIndex + 1:rightParenIndex])
repeatingLength = rightParenIndex - leftParenIndex - 1
return integerAndNonRepeating + repeating * 0.1**nonRepeatingLength * ratios[repeatingLength]
return abs(valueOf(s) - valueOf(t)) < 1e-9
// Accepted solution for LeetCode #972: Equal Rational Numbers
struct Solution;
impl Solution {
fn is_rational_equal(s: String, t: String) -> bool {
let a = Self::parse(s);
let b = Self::parse(t);
(a - b).abs() < std::f64::EPSILON
}
fn parse(s: String) -> f64 {
let n = s.len();
if let Some(dot) = s.find('.') {
let integer_part = &s[..dot];
if let Some(lparen) = s.find('(') {
let non_repeating_part = &s[dot + 1..lparen];
let repeating_part = &s[lparen + 1..n - 1];
Self::rational(integer_part, non_repeating_part, repeating_part)
} else {
let non_repeating_part = &s[dot + 1..];
Self::rational(integer_part, non_repeating_part, "")
}
} else {
s.parse::<f64>().unwrap()
}
}
fn rational(integer_part: &str, non_repeating_part: &str, repeating_part: &str) -> f64 {
let a = integer_part.parse::<f64>().unwrap_or(0.0);
let n = non_repeating_part.len();
let b = non_repeating_part.parse::<f64>().unwrap_or(0.0);
let m = repeating_part.len();
let c = repeating_part.parse::<f64>().unwrap_or(0.0);
let mut d = 0.0;
for _ in 0..m {
d *= 10.0;
d += 9.0;
}
let mut e = 1.0;
for _ in 0..n {
e *= 10.0;
}
if n == 0 && m == 0 {
return a;
}
if n == 0 {
return a + c / d;
}
if m == 0 {
return a + b / e;
}
a + (b + c / d) / e
}
}
#[test]
fn test() {
let s = "0.(52)".to_string();
let t = "0.5(25)".to_string();
let res = true;
assert_eq!(Solution::is_rational_equal(s, t), res);
let s = "0.1666(6)".to_string();
let t = "0.166(66)".to_string();
let res = true;
assert_eq!(Solution::is_rational_equal(s, t), res);
let s = "0.9(9)".to_string();
let t = "1.".to_string();
let res = true;
assert_eq!(Solution::is_rational_equal(s, t), res);
}
// Accepted solution for LeetCode #972: Equal Rational Numbers
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #972: Equal Rational Numbers
// class Solution {
// public boolean isRationalEqual(String s, String t) {
// return Math.abs(valueOf(s) - valueOf(t)) < 1e-9;
// }
//
// private static double[] ratios = new double[] {1.0, 1.0 / 9, 1.0 / 99, 1.0 / 999, 1.0 / 9999};
//
// private double valueOf(final String s) {
// if (!s.contains("("))
// return Double.valueOf(s);
//
// // Get the indices..
// final int leftParenIndex = s.indexOf('(');
// final int rightParenIndex = s.indexOf(')');
// final int dotIndex = s.indexOf('.');
//
// // integerAndNonRepeating := <IntegerPart><.><NonRepeatingPart>
// final double nonRepeating = Double.valueOf(s.substring(0, leftParenIndex));
// final int nonRepeatingLength = leftParenIndex - dotIndex - 1;
//
// // repeating := <RepeatingPart>
// final int repeating = Integer.parseInt(s.substring(leftParenIndex + 1, rightParenIndex));
// final int repeatingLength = rightParenIndex - leftParenIndex - 1;
// return nonRepeating + repeating * Math.pow(0.1, nonRepeatingLength) * ratios[repeatingLength];
// }
// }
Use this to step through a reusable interview workflow for this problem.
Simulate the process step by step — multiply n times, check each number up to n, or iterate through all possibilities. Each step is O(1), but doing it n times gives O(n). No extra space needed since we just track running state.
Math problems often have a closed-form or O(log n) solution hidden behind an O(n) simulation. Modular arithmetic, fast exponentiation (repeated squaring), GCD (Euclidean algorithm), and number theory properties can dramatically reduce complexity.
Review these before coding to avoid predictable interview regressions.
Wrong move: Temporary multiplications exceed integer bounds.
Usually fails on: Large inputs wrap around unexpectedly.
Fix: Use wider types, modular arithmetic, or rearranged operations.