166. Fraction to Recurring Decimal
2021年寒假已经回家好几天了,在家稍作休息了一下,继续刷题。这两天在家有点着凉了,今天稍微有点感冒,但是刷题还是不能停。
今天我们看一下leetcode上 第166题
这道题是将两个正数的除法结果保存为string类型。如果除法结果是循环小数,需要把循环部分用括号括起来。
例如:
Input: numerator = 1, denominator = 2
Output: "0.5"
Input: numerator = 2, denominator = 1
Output: "2"
Input: numerator = 2, denominator = 3
Output: "0.(6)"
Input: numerator = 4, denominator = 333
Output: "0.(012)"
Input: numerator = 1, denominator = 5
Output: "0.2"
其中numerator指的是被除数,denominator 指的是除数,它们的限制条件是:
-231 <= numerator, denominator <= 231 - 1
denominator != 0
这道题我目前看到leetcode上反对的人居多呀,可能大家都觉得这道题有些边界条件比较坑吧,我是提交了15次才AC的,难受的一批😭
其实这道题算法大家上小学的时候就学过了,基本上就是你小学的时候在纸上计算两个正数除法的过程,所以我们只是用代码把这个过程表述了出来。
我们先看一个简单的例子,就是
1/6 = 0.1(6)
为什么我们知道小数点中的6是循环部分?
因为我们在除的过程中,每次都是把 本次除法结果的余数作为下一次除法过程的被除数
比方说,对于我们上面的1/6
,第一次由于不够除(即被除数比除数小),于是我们在被除数后面添0,结果中也添加0。
然后是10/6
,商1余4,然后把余数4作为下一次的被除数,去计算4/6
,同样发现不够除,于是被除数添0,用40/6
有意思的来了,这次结果商6余4,借助我们小学的知识我们就知道接下来不用算了,因为接下来算也是重复刚才的过程。
也就是说,一旦我们发现某次的被除数是在之前出现过,那么小数从现在位置就开始循环了,我们只需要定位到之前出现的那个被除数的那一次除法的商在结果小数中的位置即可。
那如果某次除法的余数是0怎么办?既然余数是0,说明接下来不用算了,整个除法的结果并不是循环小数。
除法过程为了记录某个被除数在做那次除法时对应的商的位置,我们这里使用了一个map,目的是在发现循环时能知道循环是从哪里开始的。
当然,还有一些特殊情况需要我们考虑,比如,被除数和除数之间存在负数,被除数是最小的负数等等。
所以,完整代码如下:
// 166. Fraction to Recurring Decimal.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
if (numerator == 0) return "0";
if (denominator == 1) return to_string(numerator);
if (numerator == INT_MIN && denominator == -1) {
long long tmp = (long long)numerator;
return to_string(abs(tmp));
}
long long numerator_long = numerator, denominator_long = denominator;
int tmp = 0, remain = 0;
string res = "";
map<long, int> numerator_map;
int cnt = 0;
if (numerator_long < 0 && denominator_long < 0) {
numerator_long = abs(numerator_long);
denominator_long = abs(denominator_long);
}
else if (numerator_long < 0 && denominator_long > 0) {
numerator_long = abs(numerator_long);
res += "-";
}
else if (numerator_long > 0 && denominator_long < 0) {
denominator_long = abs(denominator_long);
res += "-";
}
if (numerator_long >= denominator_long) {
tmp = numerator_long / denominator_long;
remain = numerator_long % denominator_long;
res += to_string(tmp);
if (remain != 0) {
res += ".";
numerator_long = remain;
numerator_map.insert({ numerator_long, cnt++ });
}
else return res;
}
else {
res += "0.";
numerator_map.insert({ numerator_long, cnt++ });
}
string float_part = "";
while (true) {
while (numerator_long < denominator_long) {
numerator_long *= 10;
if (numerator_long < denominator_long) {
if (!numerator_map.count(numerator_long)) {
numerator_map.insert({ numerator_long, cnt++ });
}
float_part += "0";
}
}
tmp = numerator_long / denominator_long;
remain = numerator_long % denominator_long;
float_part += to_string(tmp);
if (remain == 0) {
res += float_part;
return res;
}
else {
if (numerator_map.count(remain)) {
int left_len = numerator_map[remain];
res += float_part.substr(0, left_len) + "(" + float_part.substr(left_len) + ")";
return res;
}
else {
numerator_long = remain;
numerator_map.insert({ numerator_long, cnt++ });
}
}
}
return res;
}
};
int main()
{
//std::cout << "Hello World!\n";
Solution s;
cout << s.fractionToDecimal(1, 6) << endl;
}