Look-and-See (邊看邊說) 數列具有好玩兒而神祕的特性,本文簡要介紹它和它衍生出來的康威常數。
沿革
1977年7月1-13日,國際奧林匹克數學競賽在前南斯拉夫首都貝爾格萊德舉行,賽間,荷蘭隊非正式地給英國隊出了個難題(其實類似腦筋急轉彎),大致是這樣的:
1, 11, 21, 1211, 111221
上述數列的下一項是什麼呢?
英國隊未予答覆...
故事並沒有結束,後來,在劍橋大學執教的著名數學家約翰·霍頓·康威( John·Horton·Conway)從他的學生那兒拿到了這道題,他發現了其中的奧祕,並對它進行了分析和傳播。
康威在1986年去普林斯頓大學接任了著名的約翰·馮·諾依曼(John von Neumann)教授的位子,繼續教書。
特徵
給定種子數 d (種子數在0到9之間,非1), 那麼,該數列就可以具體化爲:
d, 1d, 111d, 311d, 13211d, 111312211d, 31131122211d, …
如果種子數是1, 具體化後的數列就是本文開頭的那個數列了。
如果種子數是22,那麼,具體化後的數列的每一項的每個數字,都是2,並且每一項都是22。
當種子數不是22 時, 具體化後的數列的各項是依次增長的。
增長率
種子數不爲22時,此數列的後項與前項比有極限,這個極限被稱爲康威常數,常用 λ 表示。
λ ≈ 1.303577269034296391257099112152551890730702504659404875754861390628550...
我想知道:這裏應該有圖片,可是爲什麼51CTO的圖片上傳的“確認”按鈕點了沒效果呢?
由於無法上傳,請查看我創建的百度詞條“Look-and-say 數列” 中的配圖.
(上圖截取自維基百科: Look-and-say sequence , 我在百度百科爲這個詞建立了詞條,感興趣的可以去看下)
上圖中的四條曲線各自是一個 Look-and-say 數列的圖示: 紅色的種子數是23,藍色的是1,紫色的是13,綠色的是312。
隨着 x 軸方向的變量不斷變大,各個曲線的斜率趨向統一,極限值就是康威常數( Conway Constant )。
用途
看起來是無用之用的一個腦筋急轉彎性質的數列,但康威卻給出了不同的回答。
康威基於這個數列建立了 Cosmological theorem,解釋了宇宙衰變(Cosmological decay),用這個數列解釋了化學元素衰變和相對原子質量之間的關係。
實現
多種編程語言均可實現這個數列,現在我給出該數列在幾種編程語言中的實現:
JavaScript 實現1
/* node las.js */ function lookAndSay(str) { return str.replace(/(.)\1*/g, function(seq, p1){return seq.length.toString() + p1}) } var num = "1"; for (var i = 10; i > 0; i--) { console.log(num); num = lookAndSay(num); }
JavaScript 實現2:
/* * @Author: suifengtec * @Date: 2017-08-22 03:45:05 * @Last Modified by: suifengtec * @Last Modified time: 2017-08-22 03:51:02 */ /* node las1.js */ function lookAndSay(digits) { var result = '', chars = (digits + ' ').split(''), lastChar = chars[0], times = 0; chars.forEach(function(nextChar) { if (nextChar === lastChar) { times++; } else { result += (times + '') + lastChar; lastChar = nextChar; times = 1; } }); return result; } (function output(seed, iterations) { for (var i = 0; i < iterations; i++) { console.log(seed); seed = lookAndSay(seed); } })("1", 10);
Lua語言的實現:
-- @Author: suifengtec -- @Date: 2017-08-22 03:51:07 -- @Last Modified by: 'suifengtec' -- @Last Modified time: 2017-08-22 03:56:18 --a lua implement of the look-and-say sequence -- lua las.lua function lookAndSay(n) local t = {1} return function() local ret = {} for i, v in ipairs(t) do if t[i-1] and v == t[i-1] then ret[#ret - 1] = ret[#ret - 1] + 1 else ret[#ret + 1] = 1 ret[#ret + 1] = v end end t = ret n = n - 1 if n > 0 then return table.concat(ret) end end end for i in lookAndSay(10) do print(i) end
PHP 實現:
<?php /** * @Author: suifengtec * @Date: 2017-08-22 03:57:46 * @Last Modified by: 'suifengtec' * @Last Modified time: 2017-08-22 03:59:52 */ /* php -S 127.0.0.1:9988 http://127.0.0.1:9988/las.php */ function lookAndSay($str) { return preg_replace_callback('#(.)\1*#', function($matches) { return strlen($matches[0]).$matches[1]; }, $str); } $num = '1'; foreach(range(1,10) as $i) { echo $num.'<br/>'; $num = lookAndSay($num); }
Python 實現:
# -*- coding: utf-8 -*- # @Author: suifengtec # @Date: 2017-08-22 04:00:59 # @Last Modified by: 'suifengtec' # @Last Modified time: 2017-08-22 04:02:27 # # Look and Say 數列的 Python 實現 # python las.py # def lookAndSay(number): result = "" repeat = number[0] number = number[1:]+" " times = 1 for actual in number: if actual != repeat: result += str(times)+repeat times = 1 repeat = actual else: times += 1 return result num = "1" for i in range(10): print(num) num = lookAndSay(num)
Rust 中的實現:
/* rustc -o rs.exe las.rs && rs */ fn las(in_seq: &[i8]) -> Vec<i8> { assert!(!in_seq.is_empty()); let mut result = Vec::new(); let mut current_number = in_seq[0]; let mut current_runlength = 1; for i in &in_seq[1..] { if current_number == *i { current_runlength += 1; } else { result.push(current_runlength); result.push(current_number); current_runlength = 1; current_number = *i; } } result.push(current_runlength); result.push(current_number); result } fn main() { let mut seq = vec![1]; for i in 0..10 { println!("{}=>{:?}", i, seq); seq = las(&seq); } }
Go 語言的實現:
/* * @Author: coolwp.com * @Date: 2017-08-22 01:55:09 * @Last Modified by: suifengtec * @Last Modified time: 2017-08-22 02:37:27 **/ package main import ( "fmt" "math" "strconv" "strings" ) // 獲取以 1 爲種子數的Look-and-say 數列任意位置的數字 func getNumberOfLookAndSaySequeceSeed1(position int) int { if position == 1 { return 1 } if position == 2 { return 11 } str := "11" for i := 3; i <= position; i++ { str += "$" length := len(str) tmp := "" cnt := 1 for j := 1; j < length; j++ { strSlice := strings.Split(str, "") if strSlice[j] != strSlice[j-1] { cntTmp := strconv.Itoa(cnt) tmp += cntTmp tmp += strSlice[j-1] cnt = 1 } else { cnt++ } } str = tmp } v, err := strconv.Atoi(str) //v, err := strconv.ParseInt(str, 10, 64) if err != nil { return -1 } if v > math.MaxInt32 { return -1 } return v } // 給定任意種子數 seed, 獲取 LookAndSay 數列的 第 position 項 func getNumberOfLookAndSaySequece(seed int, position int) int { if seed == 22 { return 22 } if position == 1 { return seed } seedStr := strconv.Itoa(seed) str := "2" + seedStr if position == 2 { v, err := strconv.Atoi(str) if err != nil { return -1 } if v > math.MaxInt32 { return -1 } return v } for i := 3; i < position; i++ { str += "$" length := len(str) tmp := "" cnt := 1 for j := 1; j < length; j++ { strSlice := strings.Split(str, "") if strSlice[j] != strSlice[j-1] { cntTmp := strconv.Itoa(cnt) tmp += cntTmp tmp += strSlice[j-1] cnt = 1 } else { cnt++ } } str = tmp } r, err := strconv.Atoi(str) if err != nil { return -1 } if r > math.MaxInt32 { return -1 } return r } func main() { position := 5 a := getNumberOfLookAndSaySequeceSeed1(position) seed := 1 pos := 5 b := getNumberOfLookAndSaySequece(seed, pos) fmt.Println(a) fmt.Println(b) }
PS: 由於這個 js 不支持 Go 語言代碼高亮,並且縮進也顯示有問題, 所以請在粘貼後執行 go fmt。
結論
有一種聲音認爲:宇宙是一個程序,這個數列和康威常數用數字支持了這種說法。
本文首發酷威普和51CTO,轉載需註明。