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 <= 4
0 <= <NonRepeatingPart>.length <= 4
1 <= <RepeatingPart>.length <= 4
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to comparing rational numbers involves converting both numbers to their decimal representations. Then, to determine if they are equal, we can compare the decimal representations up to a certain precision. The key is to convert the repeating decimals into a manageable representation to compare.
Here's how the algorithm would work step-by-step:
def are_rational_numbers_equal(rational_number_one, rational_number_two):
decimal_one = rational_to_decimal(rational_number_one)
decimal_two = rational_to_decimal(rational_number_two)
precision = 10
for i in range(precision):
if abs(decimal_one - decimal_two) < 10**(-precision):
return True
else:
return False
def rational_to_decimal(rational_number):
parts = rational_number.split('(')
non_repeating_part = parts[0]
repeating_part = ''
if len(parts) > 1:
repeating_part = parts[1][:-1]
integer_part, fractional_part = non_repeating_part.split('.') if '.' in non_repeating_part else (non_repeating_part, '')
decimal_value = float(integer_part + '.' + fractional_part) if fractional_part else float(integer_part)
# Simulate the repeating decimal expansion
for i in range(10):
decimal_value += float(repeating_part) / (10**(len(fractional_part) + len(repeating_part) * (i + 1)))
return decimal_value
The goal is to determine if two rational numbers represented as strings are equal. The clever way to do this involves converting the strings to a standard form by handling repeating decimals and then comparing them directly.
Here's how the algorithm would work step-by-step:
def equal_rational_numbers(rational_1: str, rational_2: str) -> bool:
def string_to_fraction(rational: str) -> tuple[int, int]:
if '.' not in rational:
return int(rational), 1
whole_number_part = 0
non_repeating_part = ""
repeating_part = ""
if '(' in rational:
whole_number_part, decimal_part = rational.split('.')
non_repeating_part, repeating_part = decimal_part.split('(')
repeating_part = repeating_part[:-1]
else:
whole_number_part, non_repeating_part = rational.split('.')
whole_number = int(whole_number_part)
non_repeating = int(non_repeating_part) if non_repeating_part else 0
repeating = int(repeating_part) if repeating_part else 0
len_non_repeating = len(non_repeating_part)
len_repeating = len(repeating_part)
numerator = whole_number
denominator = 1
if non_repeating_part:
numerator = numerator * (10 ** len_non_repeating) + non_repeating
denominator = 10 ** len_non_repeating
# Handling the repeating part
if repeating_part:
numerator = numerator * (10 ** len_repeating) + repeating
denominator = denominator * (10 ** len_repeating)
numerator -= whole_number * (10 ** len_non_repeating) + non_repeating
denominator -= (10 ** len_non_repeating)
return numerator, denominator
def greatest_common_divisor(first_number: int, second_number: int) -> int:
while second_number:
first_number, second_number = second_number, first_number % second_number
return first_number
def simplify_fraction(numerator: int, denominator: int) -> tuple[int, int]:
# Simplifies to lowest terms
common_divisor = greatest_common_divisor(numerator, denominator)
return numerator // common_divisor, denominator // common_divisor
numerator_1, denominator_1 = string_to_fraction(rational_1)
numerator_2, denominator_2 = string_to_fraction(rational_2)
simplified_numerator_1, simplified_denominator_1 = simplify_fraction(numerator_1, denominator_1)
simplified_numerator_2, simplified_denominator_2 = simplify_fraction(numerator_2, denominator_2)
# Compare simplified fractions
return simplified_numerator_1 == simplified_numerator_2 and simplified_denominator_1 == simplified_denominator_2
Case | How to Handle |
---|---|
Input strings are null or empty | Return true if both are null/empty or false if one is and the other isn't. |
Integer overflow during greatest common divisor (GCD) calculation | Use a data type with a larger range or modular arithmetic if appropriate, such as long, to prevent overflow during GCD calculations. |
Input strings contain non-numeric characters or invalid formatting | Validate the inputs to ensure that the strings only contain numeric characters, a forward slash, and optionally a repeating decimal section enclosed in parentheses. |
Repeating decimal part contains leading zeros | Remove any leading zeros in the repeating section before processing it to avoid misinterpreting the number. |
Repeating decimal part is all nines (e.g., 0.(9)) | Recognize and simplify such numbers to their equivalent non-repeating forms (e.g., 0.(9) == 1). |
Very long repeating decimal parts (performance) | Limit the maximum length of the repeating part to prevent excessive computation and potential denial-of-service attacks. |
Negative rational numbers | Handle the negative signs correctly and consistently throughout the comparison process. |
Divide by zero | Check for zero denominators and return false if encountered. |