題目及測試
package pid166;
/* 分數到小數
給定兩個整數,分别表示分數的分子 numerator 和分母 denominator,以字元串形式傳回小數。
如果小數部分為循環小數,則将循環的部分括在括号内。
示例 1:
輸入: numerator = 1, denominator = 2
輸出: "0.5"
示例 2:
輸入: numerator = 2, denominator = 1
輸出: "2"
示例 3:
輸入: numerator = 2, denominator = 3
輸出: "0.(6)"
*/
public class main {
public static void main(String[] args) {
int[] testTable1 = new int[]{1,2,2};
int[] testTable2 = new int[]{2,1,3};
for(int i=0;i<testTable1.length;i++){
test(testTable1[i],testTable2[i]);
}
}
private static void test(int ito,int ito2) {
Solution solution = new Solution();
String rtn;
long begin = System.currentTimeMillis();
System.out.print(ito+" "+ito2);
System.out.println();
//開始時列印數組
rtn = solution.fractionToDecimal(ito,ito2);//執行程式
long end = System.currentTimeMillis();
//System.out.println(ito + ": rtn=" + rtn);
System.out.println( " rtn=" +rtn);
// for (int i = 0; i < ito.length; i++) {
// System.out.print(ito[i]+" ");
// }//列印結果幾數組
System.out.println();
System.out.println("耗時:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
自己沒想出來
解法1(别人的)
分析:這裡面需要考慮下面幾個問題:
1、如何循環求數?
2、如何判斷重複?
3、如何結束循環?
4、會不會溢出?
對于第一個問題:如果直接除數除以被除數,然後去逐位來找,那樣的話是非常難以實作的(即使可以實作,那找循環體簡直變成了不可能事件)。那換個思路,我們每次都作除,然後取整數部分,然後餘數*10,繼續下去。這樣就簡單多了,因為取整是非常簡單的(強制類型轉換即可)。
第二個問題:如何判斷重複,對于這種思路而言,當餘數在以前的曆史中出現過,就可以判斷剩下的資料也會不斷重複。是以,我們可以存一個hashmap,key就是出現的除數,然後value就是結果數組的index值。隻要包含該key時,就可以停止了。
第三個問題:已經回答了,隻要包含有key或者除數為0時就可以停止了。
第四個問題:溢出怎麼辦?對待溢出最簡單的解決方案是将其轉換為更大的類型。
/**實作除法運算,結果傳回為String類型的浮點數。
* 必須要考慮的就是循環小數,當餘數跟之前重複的時候就出現了循環小數
* 可以根據這個來設計我們的算法*/
public String fractionToDecimal(int numerator, int denominator) {
/**首先考慮除數為0,被除數為0的特殊情況*/
if(numerator==0) return "0";
if(denominator==0) return String.valueOf(Integer.MAX_VALUE);
/**其次考慮兩個數的符号不一緻的情況*/
String res=new String();
if((numerator<0)^(denominator<0))
res=res+"-";
/**考慮到Int類型為-2^32的溢出,是以轉化為long,一定要先轉換再求絕對值
* 既然已經考慮了符号,就可以直接轉為絕對值**/
long num=Math.abs((long)numerator);
long den=Math.abs((long)denominator);
/**差別整數部分和小數部分*/
long ren=num/den;
long rem=num%den;
res=res+String.valueOf(ren);
/**沒有小數部分,直接傳回**/
if(rem==0) return res;
res+='.';
/**采用map來存儲餘數,以及該餘數對應的小數的位置,這樣友善我們為循環小數打括号*/
Map<Long,Integer> map=new HashMap<Long,Integer>();
int beg=res.length();
while(rem>0)
{
rem=rem*10;
ren=rem/den;
/**如果出現重複,需要截取出循環的部分打括号**/
if(map.containsKey(rem))
{
/**循環前**/
String part1=res.substring(0,map.get(rem));
/** 循環後*/
String part2=res.substring(map.get(rem));
res=part1+"("+part2+")";
break;
}
else
{
res+=String.valueOf(ren);
map.put(rem, beg);
}
/**更新位置計數和餘數**/
beg++;
rem=rem%den;
}
return res;
}
解法2(别人的)
類似,循環的本質是:例如
a=x*b+y 然後a=y*10,然後a=x*b+y 下一次出現的y與上一次的y相同。
注意:y不一定隻有一位,如果被除數b超過1位,比如17,y可能為15之類的,是以記錄下每次的餘數y即可。
public String fractionToDecimal(int numerator, int denominator) {
if (numerator == 0) {
return "0";
}
StringBuilder fraction = new StringBuilder();
// If either one is negative (not both)
if (numerator < 0 ^ denominator < 0) {
fraction.append("-");
}
// Convert to Long or else abs(-2147483648) overflows
long dividend = Math.abs(Long.valueOf(numerator));
long divisor = Math.abs(Long.valueOf(denominator));
fraction.append(String.valueOf(dividend / divisor));
long remainder = dividend % divisor;
if (remainder == 0) {
return fraction.toString();
}
fraction.append(".");
Map<Long, Integer> map = new HashMap<>();
while (remainder != 0) {
if (map.containsKey(remainder)) {
fraction.insert(map.get(remainder), "(");
fraction.append(")");
break;
}
map.put(remainder, fraction.length());
remainder *= 10;
fraction.append(String.valueOf(remainder / divisor));
remainder %= divisor;
}
return fraction.toString();
}