题目
解题分析
首先什么是循环小数?循环小数都存在一个循环节,后面的小数部分都是根据循环节来循环的,如何得到循环节?这就是下面讨论的问题。
- 失败例子:用的每次得到的小数结果作备忘录记录,然而,明显这个重复无法作为循环是否开始的标志
- 比如
1/333=0.003-003
循环,按上面的方式就变成了0的循环。 - 正确的应该记录每次除法的余数,这样尝试
num%333=>1->10->100->1
找到循环点。
这就是找寻循环节的正确方法,看是否出现余数循环即可,如果余数为0就是可以除的断,如果出现重复就是循环。
简而言之就是,如果除法过程中出现前面已经出现过的余数,那么就相当于后面的除法结果肯定和之前的处理是一模一样的,遂为循环。
错误代码示范
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
//处理特殊情况
if(numerator==INT_MIN&&denominator==-1){
return to_string((long long)numerator/denominator);
}
string res = "";
if(numerator==0)
return "0";
if(denominator==0)
return res;
//得到符号,因为取模运算需要全为正数
if((numerator^denominator)<0)res.push_back('-');
long long t_num = numerator>0?numerator:~((unsigned int)numerator-1);
long long t_denom = denominator>0?denominator:~((unsigned int)denominator-1);
//处理整数部分
res += to_string(t_num/t_denom);
int newNum = t_num%t_denom;
if(!newNum)//若newNum为0则说明被整除无小数部分,可以直接返回了
return res;
//处理小数部分,得到非假分数开始模拟小数除法
res.push_back('.');
//用自建数组记录下标出现重复小数部分,一旦出现重复跳出循环开始在对应 位置打上括号
int t_float = newNum*10/t_denom;
res += to_string(t_float);
newNum = newNum*10%t_denom;
int visit[10];
memset(visit,0,sizeof(visit));
while(newNum&&visit[t_float]==0){
visit[t_float] = res.size()-1;
t_float = newNum*10/t_denom;
res += to_string(t_float);
newNum = newNum*10%t_denom;
}if(newNum&&visit[t_float]){
res.pop_back();
res.insert(visit[t_float],"(");
res.push_back(')');
}
return res;
}
};
正确代码
class Solution {
public:
string fractionToDecimal(int numerator, int denominator) {
//处理特殊情况
if(numerator==INT_MIN&&denominator==-1){
return to_string((long long)numerator/denominator);
}
string res = "";
if(numerator==0)
return "0";
if(denominator==0)
return res;
//得到符号,因为取模运算需要全为正数
if((numerator^denominator)<0)res.push_back('-');//下面根据是否为正数,统一转正数(用的负数补码转正数原码的方法(注意一定要用无符号转化,否则会出现10000000...-1仍然是INT_MIN(爆了)))
long long t_num = numerator>0?numerator:~((unsigned int)numerator-1);
long long t_denom = denominator>0?denominator:~((unsigned int)denominator-1);
//处理整数部分
res += to_string(t_num/t_denom);
long long newNum = t_num%t_denom;//注意用long long防止后面可能会int溢出
if(!newNum)//若newNum为0则说明被整除无小数部分,可以直接返回了
return res;
//处理小数部分,得到非假分数开始模拟小数除法
res.push_back('.');
//用hash表记录余数和余数此时对应的除法结果对应的下标,一旦出现重复的余数便是出现循环小数
int index = res.size();
unordered_map<int,int>visit;
while(newNum&&visit.count(newNum)==0){
visit[newNum] = index++;
newNum *= 10;
res += to_string(newNum/t_denom);
newNum = newNum%t_denom;
}if(visit.count(newNum)){
res.insert(visit[newNum],"(");
res.push_back(')');
}
return res;
}
};