單鏈表和之戀和海枯石爛題之分析
兩個(gè)單鏈表(singly linked list),每一個(gè)節(jié)點(diǎn)里面一個(gè)0-9的數(shù)字,輸入就相當(dāng)于兩個(gè)大數(shù)了。然后返回這兩個(gè)數(shù)的和(一個(gè)新list)。這兩個(gè)輸入的list長(zhǎng)度相等。
要求是:
- 不用遞歸;
- 要求算法在最好的情況下,只遍歷兩個(gè)list一次 ,最差的情況下兩遍。
關(guān)于海枯石爛的分析:
原題:兩個(gè)玩家,一堆石頭,假設(shè)多于100塊,兩人依次拿,最后拿光者贏,規(guī)則是:
- 第一個(gè)人不能一次拿光所有的;
- 第一次拿了之后, 每人每次最多只能拿對(duì)方前一次拿的數(shù)目的兩倍。求先拿者必勝策略, 如果有的話。怎么證明必勝。
分析:
這是斐波那契博弈,當(dāng)且僅當(dāng)石頭個(gè)數(shù)是斐波那契數(shù)的時(shí)候先手必?cái) ?/p>
讓我們用第二數(shù)學(xué)歸納法證明:
為了方便,我們將 n
記為 f[i]
。
1、當(dāng) i=2
時(shí),因?yàn)椴荒苋咳ネ辏仁种荒苋?顆,顯然必?cái)。Y(jié)論成立。
2、假設(shè)當(dāng) i<=k
時(shí),結(jié)論成立。
則當(dāng) i=k+1
時(shí),f[i] = f[k]+f[k-1]
。
則我們可以把這一堆石子看成兩堆,簡(jiǎn)稱 k
堆和 k-1
堆。
(一定可以看成兩堆,因?yàn)榧偃缦仁值谝淮稳〉氖訑?shù)大于或等于f[k-1]
,則后手可以直接取完 f[k]
,因?yàn)?f[k] < 2*f[k-1]
)
對(duì)于 k-1
堆,由假設(shè)可知,不論先手怎樣取,后手總能取到最后一顆。下面我們分析一下后手最后取的石子數(shù) x
的情況。
如果先手第一次取的石子數(shù) y>=f[k-1]/3
,則這小堆所剩的石子數(shù)小于 2y
,即后手可以直接取完,此時(shí) x=f[k-1]-y
,則 x<=2/3*f[k-1]
。
我們來(lái)比較一下 2/3*f[k-1]
與 1/2*f[k]
的大小。即 4*f[k-1]
與 3*f[k]
的大小,對(duì)兩值作差后不難得出,后者大。
所以我們得到,x<1/2*f[k]
。
即后手取完 k-1
堆后,先手不能一下取完 k
堆,所以游戲規(guī)則沒有改變,則由假設(shè)可知,對(duì)于 k
堆,后手仍能取到最后一顆,所以后手必勝。
即 i=k+1
時(shí),結(jié)論依然成立。
那么,當(dāng) n
不是Fibonacci數(shù)的時(shí)候,情況又是怎樣的呢?
這里需要借助“Zeckendorf定理”(齊肯多夫定理):任何正整數(shù)可以表示為若干個(gè)不連續(xù)的Fibonacci數(shù)之和。
關(guān)于這個(gè)定理的證明,感興趣的同學(xué)可以在網(wǎng)上搜索相關(guān)資料,這里不再詳述。
分解的時(shí)候,要取盡量大的Fibonacci數(shù)。
比如分解85:85在55和89之間,于是可以寫成85=55+30,然后繼續(xù)分解30,30在21和34之間,所以可以寫成30=21+9,
依此類推,最后分解成85=55+21+8+1。
則我們可以把 n
寫成 n = f[a1]+f[a2]+……+f[ap]
。(a1>a2>……>ap
)
我們令先手先取完 f[ap]
,即最小的這一堆。由于各個(gè)f
之間不連續(xù),則 a(p-1) > ap + 1
,則有 f[a(p-1)] > 2*f[ap]
。即后手只能取 f[a(p-1)]
這一堆,且不能一次取完。
此時(shí)后手相當(dāng)于面臨這個(gè)子游戲(只有 f[a(p-1)]
這一堆石子,且后手先取)的必?cái)B(tài),即先手一定可以取到這一堆的最后一顆石子。
同理可知,對(duì)于以后的每一堆,先手都可以取到這一堆的最后一顆石子,從而獲得游戲的勝利。
參考博文:斐波那契博弈