這個題目由於有很多的特殊狀況,所以錯誤提交了很多次。
下面是AC代碼,耗時4ms
string fractionToDecimal(int numerator, int denominator) {
//首先對0進行判斷,以防對最終符號的異或運算結果有干擾
if(0==numerator)return "0";
if(0==denominator)return "";
//使用異或的方式,判斷兩個數相除的符號,非常好用
bool sign=(numerator<0)^(denominator<0)?true:false;
//防止溢出,使用long long
long long lnumerator=llabs(numerator),ldenominator=llabs(denominator);
long long integer=lnumerator/ldenominator;
stringstream ss;
ss<<integer;
string left=ss.str();
left=(sign?"-":"")+left;
ss.str("");ss.clear();
if(0==lnumerator%ldenominator)return left;
lnumerator%=ldenominator;
map<long long,int>loopPos;
string right="";
bool loop=false;
int index=0;
int nZero=0;
while(lnumerator){
int i=1;
while((long long)lnumerator*pow(10,i)<ldenominator)i++;
long long t=lnumerator*pow(10,i);
if(loopPos.count(t)){
loop=true;
index=loopPos[t];
nZero=i-1;
break;
}
index+=i;
loopPos.insert(pair<long long,int>(t,index));
lnumerator=t%ldenominator;
long long quotient=t/ldenominator;
for(int j=1;j<=i-1;j++)ss<<0;
ss<<quotient;
}
right=loop?ss.str().substr(0,index-1-nZero)+"("+ss.str().substr(index-1-nZero)+")":ss.str();
return left+"."+right;
}
此問題的基本思路,是確定循環小數循環開始和結束的地方,因此要使用散列表記錄曾經出現的被除數,如果重複出現,則認爲是循環小數。
循環小數結束的地方就是此時商所在的下標的前一位置。
但是循環小數開始的地方,並非是循環小數商首次出現的位置,因爲這個商之前可能出現多個前導0,個數用nZero表示。
另外,此題運算過程中,不要使用int,我的編譯器由於int和long所佔位數相同,因此,爲了避免越界,只能使用long long類型。
如果使用int類型,則可能出現INT_MIN的越界,並且此時abs(INT_MIN)依然是INT_MIN,無法在正數域進行計算。
另外,如果不打算在正數域進行計算,則餘數的處理非常麻煩,因爲在c++中,取餘運算得到的餘數的符號和被除數符號一致,
並且有可能和其他程序的規則不同,因此需要對被除數的符號進行判斷,這樣寫較爲麻煩,建議轉到正數域運算。