Skip to content

Commit ed64820

Browse files
authored
Merge pull request #1371 from shreyash3087/add/leetcode-592
Docs: Added Solutions to Leetcode 592
2 parents 84a6419 + e95ab46 commit ed64820

File tree

2 files changed

+253
-1
lines changed

2 files changed

+253
-1
lines changed

dsa-problems/leetcode-problems/0500-0599.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ export const problems =[
482482
"problemName": "592. Fraction Addition and Subtraction",
483483
"difficulty": "Medium",
484484
"leetCodeLink": "https://leetcode.com/problems/fraction-addition-and-subtraction",
485-
"solutionLink": "#"
485+
"solutionLink": "/dsa-solutions/lc-solutions/0500-0599/fraction-addition-and-subtraction"
486486
},
487487
{
488488
"problemName": "593. Valid Square",
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
---
2+
id: fraction-addition-and-subtraction
3+
title: Fraction Addition and Subtraction
4+
sidebar_label: 0592 - Fraction Addition and Subtraction
5+
tags:
6+
- Math
7+
- Simulation
8+
- String
9+
description: "This is a solution to the Fraction Addition and Subtraction problem on LeetCode."
10+
---
11+
12+
## Problem Description
13+
14+
Given a string `expression` representing an expression of fraction addition and subtraction, return the calculation result in string format.
15+
16+
The final result should be an irreducible fraction. If your final result is an integer, change it to the format of a fraction that has a denominator `1`. So in this case, `2` should be converted to `2/1`.
17+
18+
### Examples
19+
**Example 1:**
20+
21+
```
22+
Input: expression = "-1/2+1/2"
23+
Output: "0/1"
24+
```
25+
26+
**Example 2:**
27+
28+
```
29+
Input: expression = "-1/2+1/2+1/3"
30+
Output: "1/3
31+
```
32+
33+
### Constraints
34+
35+
- The input string only contains `'0'` to `'9'`, `'/'`, `'+'` and `'-'`. So does the output.
36+
- Each fraction (input and output) has the format `±numerator/denominator`. If the first input fraction or the output is positive, then `'+'` will be omitted.
37+
- The input only contains valid **irreducible** fractions, where the **numerator** and **denominator** of each fraction will always be in the range `[1, 10]`. If the denominator is `1`, it means this fraction is actually an integer in a fraction format defined above.
38+
- The number of given fractions will be in the range `[1, 10]`.
39+
- The numerator and denominator of the **final result** are guaranteed to be valid and in the range of **32-bit** int.
40+
41+
## Solution for Fraction Addition and Subtraction
42+
43+
### Approach 1: Using LCM
44+
The first obvious step to be undertaken is to split the given string into individual fractions. We split the string based on `+` and `-` sign. We store the signs in the order in which they appear in the string in sign array. Further, after getting the individual fractions, we further split the fractions based on `/` sign. Thus, we obtain the individual numerator and denominator parts. We store the same in num and den arrays respectively.
45+
46+
Now, we've got the data ready to be worked upon. In order to see the method we've used in this implementation, we'll take an example and understand the way we work on it.
47+
48+
Let's say, the given fraction is:
49+
50+
$$\frac{3}{2}+\frac{5}{3}-\frac{7}{6}$$
51+
52+
We need to equalize all the denominators so as to be able to add and subtract the numerators easily. The nearest value the denominators can be scaled upto is the LCM of all the denominators. Thus, we need to find the LCM of all the denominators and then multiply all the denominators with appropriate integer factors to make them equal to the LCM. But, in order to keep the individual fraction values unchanged, we need to multiply the individual numerators also with the same factors.
53+
In order to find the LCM, we can go as follows. We use the method lcm(a,b,c)=lcm(lcm(a,b),c). Thus, if we can compute the lcm of two denominators, we can keep on repeating the process iteratively over the denominators to get the overall lcm. To find the lcm of two numbers a and b, we use lcm(a,b)=(a∗b)/gcd(a,b). For the above example, the lcm turns out to be 6.
54+
Thus, we scale up the denominators to 6 as follows:
55+
56+
$$\frac{3*3}{2*3}+\frac{5*2}{3*2}-\frac{7}{6}$$
57+
58+
Thus, we can observe that, the scaling factor for a fraction $$\frac{num}{den}$$ is given by: $num∗x/den*x$, where x is the corresponding scaling factor. Note that, $den∗x=lcm$. Thus, $x=lcm/denx$. Thus, we find out the corresponding scaling factor $x_i$ for each fraction.
59+
60+
After this, we can directly add or subtract the new scaled numerators.
61+
62+
In the current example, we obtain $$\frac{12}{6}$$ as the result. Now, we need to convert this into an irreducible fraction. Thus, if we obtain $$\frac{num_i}{den_i}$$ as the final result, we need to find a largest factor y, which divides both $num_i$ and $den_i$. Such a number, as we know, is the gcd of $num_i$ and $den_i$.
63+
64+
Thus, to convert the result $$\frac{num_i}{den_i}$$ we divide both the numerator and denominator by the gcd of the two numbers y to obtain the final irreducible $$\frac{num_i/y}{den_i/y}$$
65+
66+
Note: A problem with this approach is that we find the lcm of all the denominators in a single go and then reduce the overall fraction at the end. Thus, the lcm value could become very large and could lead to an overflow. But, this solution suffices for the current range of numbers.
67+
68+
## Code in Different Languages
69+
70+
<Tabs>
71+
<TabItem value="cpp" label="C++">
72+
<SolutionAuthor name="@Shreyash3087"/>
73+
74+
```cpp
75+
#include <vector>
76+
#include <string>
77+
#include <sstream>
78+
#include <algorithm>
79+
80+
class Solution {
81+
public:
82+
std::string fractionAddition(std::string expression) {
83+
std::vector<char> sign;
84+
for (int i = 1; i < expression.length(); i++) {
85+
if (expression[i] == '+' || expression[i] == '-')
86+
sign.push_back(expression[i]);
87+
}
88+
std::vector<int> num, den;
89+
std::istringstream iss(expression);
90+
std::string sub, subsub;
91+
while (std::getline(iss, sub, '+')) {
92+
std::istringstream iss2(sub);
93+
while (std::getline(iss2, subsub, '-')) {
94+
if (!subsub.empty()) {
95+
std::size_t pos = subsub.find('/');
96+
num.push_back(std::stoi(subsub.substr(0, pos)));
97+
den.push_back(std::stoi(subsub.substr(pos + 1)));
98+
}
99+
}
100+
}
101+
if (expression[0] == '-') num[0] = -num[0];
102+
int lcm = 1;
103+
for (int x : den) {
104+
lcm = lcm_(lcm, x);
105+
}
106+
107+
int res = lcm / den[0] * num[0];
108+
for (int i = 1; i < num.size(); i++) {
109+
if (sign[i - 1] == '+') res += lcm / den[i] * num[i];
110+
else res -= lcm / den[i] * num[i];
111+
}
112+
int g = gcd(std::abs(res), std::abs(lcm));
113+
return std::to_string(res / g) + "/" + std::to_string(lcm / g);
114+
}
115+
116+
private:
117+
int lcm_(int a, int b) {
118+
return a * b / gcd(a, b);
119+
}
120+
121+
int gcd(int a, int b) {
122+
while (b != 0) {
123+
int t = b;
124+
b = a % b;
125+
a = t;
126+
}
127+
return a;
128+
}
129+
};
130+
131+
```
132+
</TabItem>
133+
<TabItem value="java" label="Java">
134+
<SolutionAuthor name="@Shreyash3087"/>
135+
136+
```java
137+
class Solution {
138+
public String fractionAddition(String expression) {
139+
List<Character> sign = new ArrayList<>();
140+
for (int i = 1; i < expression.length(); i++) {
141+
if (expression.charAt(i) == '+' || expression.charAt(i) == '-')
142+
sign.add(expression.charAt(i));
143+
}
144+
List<Integer> num = new ArrayList<>();
145+
List<Integer> den = new ArrayList<>();
146+
for (String sub : expression.split("\\+")) {
147+
for (String subsub : sub.split("-")) {
148+
if (subsub.length() > 0) {
149+
String[] fraction = subsub.split("/");
150+
num.add(Integer.parseInt(fraction[0]));
151+
den.add(Integer.parseInt(fraction[1]));
152+
}
153+
}
154+
}
155+
if (expression.charAt(0) == '-') num.set(0, -num.get(0));
156+
int lcm = 1;
157+
for (int x : den) {
158+
lcm = lcm_(lcm, x);
159+
}
160+
161+
int res = lcm / den.get(0) * num.get(0);
162+
for (int i = 1; i < num.size(); i++) {
163+
if (sign.get(i - 1) == '+') res += lcm / den.get(i) * num.get(i);
164+
else res -= lcm / den.get(i) * num.get(i);
165+
}
166+
int g = gcd(Math.abs(res), Math.abs(lcm));
167+
return (res / g) + "/" + (lcm / g);
168+
}
169+
170+
public int lcm_(int a, int b) {
171+
return a * b / gcd(a, b);
172+
}
173+
174+
public int gcd(int a, int b) {
175+
while (b != 0) {
176+
int t = b;
177+
b = a % b;
178+
a = t;
179+
}
180+
return a;
181+
}
182+
}
183+
```
184+
185+
</TabItem>
186+
<TabItem value="python" label="Python">
187+
<SolutionAuthor name="@Shreyash3087"/>
188+
189+
```python
190+
from typing import List
191+
192+
class Solution:
193+
def fractionAddition(self, expression: str) -> str:
194+
sign: List[str] = []
195+
for i in range(1, len(expression)):
196+
if expression[i] in ['+', '-']:
197+
sign.append(expression[i])
198+
199+
num: List[int] = []
200+
den: List[int] = []
201+
for sub in expression.split('+'):
202+
for subsub in sub.split('-'):
203+
if subsub:
204+
fraction = subsub.split('/')
205+
num.append(int(fraction[0]))
206+
den.append(int(fraction[1]))
207+
208+
if expression[0] == '-':
209+
num[0] = -num[0]
210+
211+
lcm = 1
212+
for x in den:
213+
lcm = self.lcm(lcm, x)
214+
215+
res = lcm // den[0] * num[0]
216+
for i in range(1, len(num)):
217+
if sign[i-1] == '+':
218+
res += lcm // den[i] * num[i]
219+
else:
220+
res -= lcm // den[i] * num[i]
221+
222+
g = self.gcd(abs(res), abs(lcm))
223+
return f"{res // g}/{lcm // g}"
224+
225+
def lcm(self, a: int, b: int) -> int:
226+
return a * b // self.gcd(a, b)
227+
228+
def gcd(self, a: int, b: int) -> int:
229+
while b != 0:
230+
t = b
231+
b = a % b
232+
a = t
233+
return a
234+
```
235+
</TabItem>
236+
</Tabs>
237+
238+
## Complexity Analysis
239+
240+
### Time Complexity: $O(nlogx)$
241+
242+
> **Reason**: Euclidean GCD algorithm takes O(log⁡(ab)) time for finding gcd of two numbers a and b. Here n refers to the number of fractions in the input string and x is the maximum possible value of denominator.
243+
244+
### Space Complexity: $O(n)$
245+
246+
> **Reason**: Size of num, denand sign list grows upto n.
247+
248+
## References
249+
250+
- **LeetCode Problem**: [Fraction Addition and Subtraction](https://leetcode.com/problems/fraction-addition-and-subtraction/description/)
251+
252+
- **Solution Link**: [Fraction Addition and Subtraction](https://leetcode.com/problems/fraction-addition-and-subtraction/solutions/)

0 commit comments

Comments
 (0)