Java遍历完数的一些思考
生活随笔
收集整理的這篇文章主要介紹了
Java遍历完数的一些思考
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目:打印出1~10000以內所有的完數
1.分析1
- 如果一個數恰好等于它的因子之和,則稱該數為“完全數”。引用百度百科-完全數,如6=1+2+3
- 不包括數本身的所有的因子之和等于這個數,所以1不符合要求;
- 遍歷所有2~10000的數,并且嵌套遍歷0到該數范圍內的所有預備因子,如果該數模預備因子等于0,則該預備因子為該數的因子,定義一個計數器,將所有因子累加,如果累加結果等于該數本身,即這個數為完數;
- 為了便于比較運算效率,引入System.currentTimeMillis()方法記錄遍歷前后的系統當前毫秒值;
2.代碼:
public class PerfectNumberDemo {public static void main(String[] args) {long start = System.currentTimeMillis();for (int num = 2; num <= 10000 ; num ++ ) {int sum = 0;for (int divisor = 1 ; divisor < num ; divisor ++) {if (num % divisor == 0 ) {sum = divisor + sum;}}if (sum == num) {System.out.println(num);}}long end = System.currentTimeMillis();System.out.println("遍歷全部完數所使用的時間: " + (end - start) + " 毫秒");} } 復制代碼- 運行結果:
3.一點思考
- 判斷10000這個數是否是完數需要遍歷預備因子9999次,判斷9999這個數是否是完全數需要遍歷預備因子9998次,以此類推,根據等差數列求和公式需要遍歷9998*(9999 + 2) / 2 = 49,994,999次,顯然效率很低,需要進一步優化;
- 經過分析,完數的最大因子不會超過他本身的一半,所以可以把divisor < num改成divisor <= num / 2;
- 繼續分析,如果數num的第2因子divisor2,則(num / divisor2)也一定是num的因子,則(num / divisor2)到num之間一定不會有因子出現,下一步預備因子遍歷范圍縮小到divisor2 ~ (num / divisor2);
- 繼續,如果數num的第3個因子divisor3,則(num / divisor3)也一定是num的因子,則(nmu / divisor3)到(num / divisor2)之間一定不會有因子出現,下一步預備因子遍歷范圍縮小到divisor3 ~ (num / divisor3),以此類推即可;
- 將所有因子累加到計數器sum中,然后比較sum - num == num 即可,但是有個例外;
- 例如num=16,第3個因子divisor3是4,則(num / divisor3)還是4,因子4不能重復計入計數器,所以需要使用if ··· else if ···語句判斷兩種情況,分別累加因子;
4.代碼優化
public class PerfectNumberTest {public static void main(String[] args) {int count = 0;//定義一個計數器System.out.println("1~10000范圍內的所有完數如下:");long start = System.currentTimeMillis();for (int num = 2; num <= 10000 ; num ++ ) {int sum = 0;//定義一個因子求和公式for (int divisor = 1 ; divisor <= num / divisor ; divisor ++) {if (num % divisor == 0 && divisor != num / divisor) {//若num開根號結果不是他的因子sum = divisor + (num / divisor) + sum;//則num/divisor也一定是他的因子} else if (num % divisor == 0 && divisor == num / divisor) {//若num開根號的結果是他的因子sum = divisor + sum;//則只把因子(num/divisor重復因子)賦值給sum}}if ((sum - num) == num) {//如果因子之和-該數等于該數,則這個數就是完數count ++;//計數器加一System.out.println("第 " + count +" 完數是: " + num);//輸出完數}}long end = System.currentTimeMillis();System.out.println("遍歷全部完數所使用的時間: " + (end - start) + " 毫秒");} } 復制代碼5.執行結果
6.說在后面
- 本人電腦是13年購買,配置一般,所以結果僅說明運行效率問題;
- 49,994,999+次遍歷只用了400多毫秒,也就一眨眼的功夫,一般的算法優化對運行效率提升有限;
- int類型取值范圍到21億,代碼中有多個數累加求和,很可能求和結果超出int類型范圍,影響運行結果,所以建議求完數的范圍不要太大.
轉載于:https://juejin.im/post/5a34e6c4518825696f7e121c
總結
以上是生活随笔為你收集整理的Java遍历完数的一些思考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何对依赖ZooKeeper的代码写单元
- 下一篇: Java内存区域与内存溢出