Look-and-Say 数列
Look-and-See (边看边说) 数列具有好玩儿而神秘的特性,本文简要介绍它和它衍生出来的康威常数。
沿革
1977年7月1-13日,国际奥林匹克数学竞赛在前南斯拉夫首都贝尔格莱德举行,赛间,荷兰队非正式地给英国队出了个难题(其实类似脑筋急转弯),大致是这样的:
1
|
1, 11, 21, 1211, 111221 |
上述数列的下一项是什么呢?
英国队未予答复...
故事并没有结束,后来,在剑桥大学执教的著名数学家约翰·霍顿·康威( John·Horton·Conway)从他的学生那儿拿到了这道题,他发现了其中的奥秘,并对它进行了分析和传播。
康威在1986年去普林斯顿大学接任了著名的约翰·冯·诺依曼(John von Neumann)教授的位子,继续教书。
特征
给定种子数 d (种子数在0到9之间,非1), 那么,该数列就可以具体化为:
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
1
2
3
4
5
6
7
8
9
10
11
12
|
/* 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/* * @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语言的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
-- @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 实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<?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 实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
# -*- 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 中的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
/* 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 语言的实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/* * @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。
结论
有一种声音认为:宇宙是一个程序,这个数列和康威常数用数字支持了这种说法。