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 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 intint {

    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 intint {

    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。

结论

有一种声音认为:宇宙是一个程序,这个数列和康威常数用数字支持了这种说法。

时间: 2024-10-25 15:18:46

Look-and-Say 数列的相关文章

用递归和非递归的方法输出斐波那契数列的第n个元素(C语言实现)

费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列. 在数学上,费波那契数列是以递归的方法来定义: {\displaystyle F_{0}=0} {\displaystyle F_{1}=1} {\displaystyle F_{n}=F_{n-1}+F_{n-2}}(n≧2) 用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出.首几个费波那契系数是: 0, 1, 1, 2, 3

HDU 5783 Divide the Sequence(数列划分)

HDU 5783 Divide the Sequence(数列划分) Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)   Problem Description - 题目描述 Alice has a sequence A, She wants to split A into as much as possible continuous subsequences, satisfy

2015.9.11模拟赛 codevs 4159【hzwer的迷の数列】

题目描述 Description hzwer找了一个人畜无害的迷の数列…… 现在hzwer希望对这个数列进行一些操作,请你来回答hzwer的问题. 操作一:查询第i个数的大小 操作二:把第i个数的大小改成x 操作三:将整个序列反转.即把第i个数放到第n-i+1个. 输入描述 Input Description 输入数据第一行两个数n,m,表示数列长度和操作数. 第二行n个数,表示n个元素初始值. 以下m行,每行开头一个数opr,表示操作种类. opr=1,则后面接一个数i,表示查询第i个数大小.

数列有序

此题可先将排好的数列计入数组,然后讲要插入的数放进,再重新排列: 另一种方法

Fibonacci斐波拉契数列----------动态规划DP

n==10 20 30 40 50 46 体验一下,感受一下,运行时间 #include <stdio.h>int fib(int n){ if (n<=1)     return 1; else            return fib(n-1)+fib(n-2); }int main( ){ int n; scanf("%d",&n); printf("%d\n" ,fib(n) );} 先 n==10 20 30 40 50 46

[HAOI2009]逆序对数列

题目描述 对于一个数列{ai},如果有i<j且ai>aj,那么我们称ai与aj为一对逆序对数.若对于任意一个由1~n自然数组成的数列,可以很容易求出有多少个逆序对数.那么逆序对数为k的这样自然数数列到底有多少个? 输入输出格式 输入格式: 第一行为两个整数n,k. 输出格式: 写入一个整数,表示符合条件的数列个数,由于这个数可能很大,你只需输出该数对10000求余数后的结果. 输入输出样例 输入样例#1: 4 1 输出样例#1: 3 说明 样例说明: 下列3个数列逆序对数都为1:分别是1 2

Pell数列

描述Pell数列a1, a2, a3, ...的定义是这样的,a1 = 1, a2 = 2, ... , an = 2 * an ? 1 + an - 2 (n > 2).给出一个正整数k,要求Pell数列的第k项模上32767是多少.输入第1行是测试数据的组数n,后面跟着n行输入.每组测试数据占1行,包括一个正整数k (1 ≤ k < 1000000).输出n行,每行输出对应一个输入.输出应是一个非负整数.样例输入 2 1 8 样例输出 1 408 源代码 #include<stdio

[考试] 组合数,数列

Fseq[问题描述]一个长度为 N+M 的数列,里面有 N 个+1,M 个-1如果一个这样的数列被称作 F 序列(Fadeness) , 当且仅当它的任意前缀和均非负.for example :1,-1,1,1,-1 is a Fadeness1,-1,-1,1,1 is not because S(3) <0求一个数列是 Fadensee 的概率.[输入格式]第一行, Test , 表示测试数据的组数.每个数据 有两个数 N,M[输出格式]对于每组数据,输出一个实数(保留到小数点后 6 位)[

luoguP1415 拆分数列 [dp]

题目描述 给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数.如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小:如果有多组解,则使得第一个数尽量大:如果仍有多组解,则使得第二个数尽量大,依次类推……). 输入输出格式 输入格式: 共一行,为初始的数字. 输出格式: 共一行,为拆分之后的数列.每个数之间用逗号分隔.行尾无逗号. 输入输出样例 输入样例#1: [1] 3456 [2] 3546 [3] 3526 [4] 0001 [5] 100000