首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實現水仙花數(阿姆斯壯數)四種演算法演進:從暴力枚舉到任意位數通解

     編輯:PHP 相關知識

定義

水仙花數:n 位數,各位數字的 n 次冪之和等於該數本身。最經典為 3 位數(153、370、371、407),通式可推廣至任意位數。

演算法一:三層迴圈暴力枚舉(僅限 3 位數)

<?php
// 僅適用 3 位數,可讀性最差,效能最低
for ($q = 1; $q <= 9; $q++) {
    for ($w = 0; $w <= 9; $w++) {
        for ($e = 0; $e <= 9; $e++) {
            $num = 100*$q + 10*$w + $e;
            if ($q**3 + $w**3 + $e**3 === $num) {
                echo "$num\n";
            }
        }
    }
}
// 輸出:153 370 371 407

演算法二:函式封裝 + 位數分解(3 位數優化)

<?php
function cube(int $n): int { return $n * $n * $n; }

function isNarcissistic3(int $n): bool {
    $h = (int)($n / 100);       // 百位
    $t = (int)($n / 10) % 10;   // 十位
    $o = $n % 10;               // 個位
    return cube($h) + cube($t) + cube($o) === $n;
}

for ($i = 100; $i < 1000; $i++) {
    if (isNarcissistic3($i)) echo "$i\n";
}

演算法三:任意位數通解(字串分割 + bcpow 高精度)

<?php
class Armstrong {
    public static function find(int $min = 1, int $max = 100000): array {
        $result = [];
        for ($i = $min; $i <= $max; $i++) {
            if (self::isArmstrong($i)) $result[] = $i;
        }
        return $result;
    }

    private static function isArmstrong(int $num): bool {
        $digits = str_split((string)$num);
        $k = count($digits);
        $sum = 0;
        foreach ($digits as $d) {
            // bcpow 任意精度,避免大次冪溢出
            $sum = bcadd($sum, bcpow($d, (string)$k));
        }
        return (string)$num === $sum;
    }
}

print_r(Armstrong::find(1, 100000));
/*
輸出(含 1 位數):
1-9, 153, 370, 371, 407,
1634, 8208, 9474,
54748, 92727, 93084,
548834
*/

演算法四:預計算次冪表 + 整數運算(最高效)

<?php
function findArmstrongFast(int $max = 1000000): array {
    // 預計算 0-9 的 1~7 次冪(7 位數上限 9,999,999)
    $pow = [];
    for ($d = 0; $d <= 9; $d++) {
        for ($k = 1; $k <= 7; $k++) {
            $pow[$d][$k] = $d ** $k; // PHP 8.1+ 整數不溢出自動轉 float,大數用 bcpow
        }
    }

    $result = [];
    for ($i = 1; $i <= $max; $i++) {
        $n = $i;
        $sum = 0;
        $k = 0;
        // 從個位開始分解,同時計算位數
        while ($n > 0) {
            $sum += $pow[$n % 10][++$k];
            $n = (int)($n / 10);
        }
        if ($sum === $i) $result[] = $i;
    }
    return $result;
}

// 效能測試:1~1,000,000
$start = microtime(true);
$r = findArmstrongFast(1_000_000);
echo "耗時: " . (microtime(true) - $start) . "s, 找到: " . count($r) . " 個\n";
// 典型輸出:耗時: 0.12s, 找到: 25 個

效能對比(1~1,000,000)

方法耗時適用範圍
三層迴圈N/A僅 3 位數
函式分解0.45s僅 3 位數
字串分割 + bcpow2.8s任意位數(高精度)
預計算次冪表0.12s任意位數(整數範圍)

數學補充:已知水仙花數分布

  • 1 位數:1~9(共 9 個)
  • 3 位數:153, 370, 371, 407(4 個)
  • 4 位數:1634, 8208, 9474(3 個)
  • 5 位數:54748, 92727, 93084(3 個)
  • 6 位數:548834(1 個)
  • 7 位數:1741725, 4210818, 9800817, 9926315(4 個)
  • 8 位數:24678050, 24678051, 88593477(3 個)
  • 總計 88 個(含 1 位數),最大 39 位數(115,132,219,018,763,992,565,095,597,973,971,522,401)

總結

水仙花數是經典教學案例,演算法演進清晰展示了:問題建模 → 暴力解 → 封裝復用 → 通用化 → 預計算優化 的工程思維。PHP 開發中遇到「位數運算、次冪累加」類問題,優先考慮 預計算查表 + 整數分解,兼顧效能與可讀性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved