演算法趣題:迴文十進位制數

黃志斌發表於2017-08-14

今天下午收到高宇涵老師的寄來的《程式設計師的演算法趣題》,這本書的第 1 題是迴文十進位制數

求用十進位制、二進位制、八進位制表示都是迴文數的所有數字中,大於十進位制數 10 的最小值。

書中的解題思路是:

因為是二進位制的迴文數,所以如果最低位是 0,那麼相應地最高位也是 0。但是,以 0 開頭肯定是不恰當的,由此可知最低位為 1。

如果用二進位制表示時最低位為 1,那這個數一定是奇數,因此只考慮奇數的情況就可以。接下來可以簡單地編寫程式,從 10 的下一個數字 11 開始,按順序搜尋。

書中使用 Ruby 和 JavaScript 編寫程式求解,如果使用 Haskell 編寫程式求解:

import Data.Digits ( digitsRev )
main = print $ head $ filter (\n -> and [(\a -> a ==
  reverse a) $ digitsRev b n | b <- [10,8,2]]) [11,13..]

這個程式執行 0.01 秒後,得到答案:

58510 = 11118 = 10010010012

進階

書中的演算法對於這個問題是恰當的,但是如果要尋找更大的滿足要求的數,就太慢了。我們可以事先構造出十進位制奇迴文數,以加快尋找速度。由此,我使用 Haskell 語言編寫以下程式:

import Data.Digits ( digitsRev )
main = print $ concat [filter (\n -> and [(\a -> a == reverse a) $
  digitsRev b n | b <- [2,8]]) [read $ x : s ++ y ++ reverse s ++ [x]
  | x <- "13579", s <- if n /= 0 then [replicate (n - length t) '0'
  ++ t | i <- [0 .. 10^n-1], let t = show i] else [""], y <- if z
  then map show [0..9] else [""]] | n <- [0..3], z <- [False, True]]

簡要說明:

  • 第 2 至 3 行檢查所給的十進位制奇迴文數是不是二進位制和八進位制迴文數。
  • 最後一行 z = False 時生成 xabccbax 形狀的十進位制奇迴文數,x 是奇數(見第 4 行)。
  • 最後一行 z = True 時生成 xabcycbax 形狀的十進位制奇迴文數,第 4 行的 s 就是"abc" 。
  • 最後一行的 n 決定生成的十進位制奇迴文數的位數,共 2n+2 (z = False) 或 2n+3 (z = True) 位。

在這個程式中的最後一行中,n 從 0 至 3,用於在 2 位至 9 位的十進位制奇迴文數中尋找。執行這個程式,瞬間(用時 0.4 秒)得到:

71984891710 = 52720027258 = 1010101110100000000101110101012

但是,我沒有找到更大的滿足要求的數。不知道是否還存在這樣的數。

相關文章