Look-and-Say 數列

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,轉載需註明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章