這多是最快的自冪數算法

這多是最快的自冪數算法

  • 什麼是自冪數
    • 自冪數是指一個 n 位數,它的每一個位上的數字的 n 次冪之和等於它自己。(例如:當n爲3時,有1^3 + 5^3 + 3^3 = 153,153便是n爲3時的一個自冪數)
    • 自冪數包括:獨身數、水仙花數、四葉玫瑰數、五角星數、六合數、北斗七星數、八仙數、九九重陽數、十全十美數
      ---摘自百度百科
  • 如何計算自冪數
    • 最近研究了一下水仙花數,完了以後就天然而然的優化成了計算自冪數的算法...
    • 個人思路是,首先,若是要計算的是100-1000之間的水仙花數
      • 一個循環,從100-1000 (i=100; i<1000)
      • 每次循環先取出i的個位,十位,百位數
      • 將個位,十位,百位的三次方和i進行比較,相等則打印輸出
      • 如下代碼
      for (var i = 100; i < 1000; i++) {
        var hundred = Math.floor(i / 100);
        var decade = Math.floor((i / 10) % 10);
        var single = i % 10;
        if (hundred * hundred * hundred + decade * decade * decade + single * single * single === i) {
        console.log(i); //153 370 371 407
        }
      }
  • 通過思考以後,代碼改爲了這個樣子
for (var i = 100; i < 1000; i++) {
    var s = i + "";
    var hundred = +s[0];
    var decade = +s[1];
    var single = +s[2];
    if (Math.pow(hundred, 3) + Math.pow(decade, 3) + Math.pow(single, 3) === i) {
        console.log(i); //153 370 371 407
    }
}
  • 而後發現上邊定義變量的步驟徹底是重複的,修改成
for (var i = 100; i < 10000; i++) {
    var s = i + "";
    var sum=0;
    for (var k = 0; k < 3; k++) {
        sum += Math.pow(s[k], 3)
    }
    if (sum === i) {
        console.log(i); //153 370 371 407
    }
}
  • 以上代碼能夠優化爲計算自冪數的算法
var max=3;//最大位數
var len=Math.pow(10, max);
for (var i = 100; i < len; i++) {
    var s = i + "";
    var sum=0;
    for (var k = 0; k < s.length; k++) {
        sum += Math.pow(s[k], s.length)
    }
    if (sum === i) {
        console.log(i); //153 370 371 407
    }
}
  • 有沒有發現有什麼不一樣,除了上邊的循環次數作了修改以外,就只是吧3修改爲了s.length 這樣是4位數的時候就會計算4個數的4次方,5個數...
  • 由於咱們能夠確定s[k]是一個數字,因此能夠這樣來獲取這個字符串表明的值,比系統隱式轉換的效率更高
var max=3;//最大位數
var len=Math.pow(10, max);
for (var i = 100; i < len; i++) {
    var s = i + "";
    var sum=0;
    for (var k = 0; k < s.length; k++) {
        sum += Math.pow(s[k] - '0', s.length)
    }
    if (sum === i) {
        console.log(i); //153 370 371 407
    }
}
  • 到了這一步 一個簡單的自冪數算法就已經完成了,以後我又本身作了兩次優化
  • 初版本是 eight1 (代碼在下邊)
  • 第一次優化後的是eight2 具體是本身維護了一個表明當前數值的數組,而再也不從數值中逐個轉換,優化後速度提高了80%大概
  • 第二次優化是最大的,就是提早吧幾的幾回方算好了,由於我發現實際運行中這個的計算次數是在是太多了....
  • 優化後速度提高了數十倍
  • 代碼最初寫的是java,後來由於發現js執行更快就改爲了js
"Use strict";
function eight1(len) {
    var max = Math.pow(10, len);//初始化最大值
    var arr = [];//結果數組
    for (var j = 100; j < max; j++) {
        var s = j + "";
        var sum = 0;
        for (var k = 0; k < s.length; k++) {
            sum += Math.pow(s[k] - '0', s.length);
        }
        if (sum == j) {
            arr.push(j);
        }
    }
    console.log("eight1", arr);
}
function eight2(len) {
    var num = [];//num是我維護的數組
    //根據len初始化數組 len爲6時 [0,0,1,0,0,0] 表明100
    for (let o = 0; o < len; o++) {
        if (o === 2) {
            num[o] = 1;
        } else {
            num[o] = 0;
        }
    }
    var cs = 3;//當前最大值是幾位數
    var len = Math.pow(10, num.length) - 1;//循環次數
    var c;//本次計算了幾位數
    var arr = [];//結果數組
    for (var j = 100; j < len; j++) {
        var t = 0;
        c = 0;
        num[t]++;
        //對數組進行+1操做,滿10進1
        while (num[t] >= 10) {
            c++;
            num[t] = 0;
            t++;
            num[t]++;
        }
        if (c >= cs) {//若是本次到了比最大值更大的位數,則最大位數+1
            cs++;
        }
        var sum = 0;
        for (var k = 0; k < cs; k++) {
            sum += Math.pow(num[k], cs);
        }
        if (sum == j + 1) {
            arr.push(sum);
        }
    }
    console.log("eight2", arr);
}

function eight3(len) {
    var num = [];
    for (let o = 0; o < len; o++) {
        if (o === 2) {
            num[o] = 1;
        } else {
            num[o] = 0;
        }
    }
    var arr = [];
    var result = [];//提早把1-9 ^3 ~ 1-9 ^ len 的值給計算好,存放在數組中,而後使用時根據數組取值便可 
    for (var i = 0; i <= 9; i++) {
        result[i] = [];//由於是雙層數組,因此這裏作初始化
        for (var j = 3; j <= len; j++) {
            result[i][j] = Math.pow(i, j);//計算結果,賦值
        }
    }
    var cs = 3;
    var len = Math.pow(10, num.length) - 1;
    var c;
    for (var j = 100; j < len; j++) {
        var t = 0;
        c = 0;
        num[t]++;
        while (num[t] >= 10) {
            c++;
            num[t] = 0;
            t++;
            num[t]++;
        }
        if (c >= cs) {
            cs++;
        }
        var sum = 0;
        for (var k = 0; k < cs; k++) {
            sum += result[num[k]][cs];//這裏直接取出結果行了,不須要計算
        }
        if (sum == j + 1) {
            console.log(sum);
            arr.push(sum);
        }
    }
    console.log("eight2_2", arr);
}
console.warn("eight1  start");
console.time();
eight1(6);
console.timeEnd();

console.warn("eight2  start");
console.time();
eight2(6);
console.timeEnd();

console.warn("eight3  start");
console.time();
eight3(6);
console.timeEnd();
  • 能夠吧代碼拷貝走,本身跑一下試試
  • 下面是我在本身電腦上跑的速度對比 10次的平均值
  • 單位 ms
  • 8位以上的除了eight3其餘的沒有跑,eight3也只跑了一次
3 位 4 位 5 位 6 位 7 位 8 位 9 位 10 位
eight1 0.9 3.2 42.1 484.4 5638.8 - - -
eight2 0.9 2.8 31.1 359.9 4227.2 - - -
eight3 0.7 0.3 1.3 12.4 139.3 1670.0 19490.7 235028.1

相關文章
相關標籤/搜索