2016網易機試編程題中的字元串問題?
由a,b,c三個字元組成的長度為n的字元串共3^n種,包含(abc,acb,bac,bca,cab,cba)任意一個子串的字元串有多少種?
題主主要想問的是關於概率方面的解答。感覺像是高中的排列組合問題,但又做不出來。編程的話,將abc用124分別表示,result表示結果,深度遍歷整個樹(棧來存儲狀態),碰到最後三個數加起來為7的情況下剪枝,result += 3^x(x為總層數減去當層數)。
記長度為k,不包含該集合任意子串,最後兩位相同的字元串數目為
記長度為k,不包含該集合任意子串,最後兩位不同的字元串數目為
則我們要求的是遞推可解,時間複雜度O(n)。進一步地,寫成矩陣形式
矩陣特徵值為所以
注意到,因此當k充分大時,這一項可以忽略。實際上,只需取k=4就有所以我們要求的是包含該集合中子串的字元串,即為複雜度O(n)
主要工作是找出DP的狀態轉移方程。import sys
max = 31
if __name__ == "__main__":
n = int(sys.stdin.readline().strip())
t1 = [0, 0, 0] # 後兩位一樣 為真
t2 = [0, 0, 0] # 後兩位不一樣 為真
t3 = [0, 0, 3] # 後兩位一樣 為假
t4 = [0, 3, 6] # 後兩位不一樣 為假
for i in range(3, max):
x1, x2, x3, x4 = t1[-1], t2[-1], t3[-1], t4[-1]
t1.append(x1 + x2)
t2.append(2 * x1 + 2 * x2 + x4)
t3.append(x3 + x4)
t4.append(2 * x3 + x4)
ans = [t3[i] + t4[i] for i in range(max)]
print(ans[n])
備忘錄式DP,簡單暴力比對了下結果,應該沒啥問題,當然細節性能有待改進,但是算到n=990也是瞬間出結果(因為python遞歸到1000層就異常了)
import sys
n = int(sys.argv[1])
mem = {}
def f(s):
if len(set(s[-3 :])) == 3:
return 0
if len(s) == n:
return 1
last = s[-2 :]
key = len(s), last
if key in mem:
return mem[key]
mem[key] = r = sum([f(s + c) for c in "abc"])
return r
print 3 ** n - f("")
Richard的方法,到矩陣那一步,然後算個快速冪,logn級別時間得到精確解。
不過如果用C/Cpp你還得寫個高精度計算……
設表示長度為,不包含6個目標串,且結尾兩個字元相同的字元串數量;
設表示長度為,不包含6個目標串,且結尾兩個字元不同的字元串數量;設表示長度為,包含目標串的字元串數量。初始化:
當時, 得到如下遞推公式;;;對這道題來講n大概20左右吧,畢竟種類的總數是,所以這樣所應該就OK了,複雜度O(n)。如果(拋開這道題)n可以取很大,比如這種數量級,遞推關係不變,可以考慮矩陣加速的做法:
複雜度O(log n)純數學方法,這題可以求出通項公式的後一位可能的情況與前兩位有關,前兩位相同則這一位有三種情況,前兩位不同則這一位有兩種情況,這樣就可以得出後面的通項公式,不知道題主怎麼看
提供一個相對易懂的思路。
求包含的字元串數量,等價於求總數減去不包含的數量(題目好像也這樣提示了)。由於給出的字元串長度只有3位,可以手工構造一下所有的狀態。一個長度為n的字元串可以由前n-1個字元加上第n個字元組成。設一個長度為2的字元串,它的第一位表示某字元串的第n-1個字元,第二位表示某字元串的第n位字元,將它枚舉出來得:aa、bb、cc、ab、ac、ba、bc、ca、cb。根據題目構造轉移矩陣(1表示可以拼接在一起,反之亦然。aa和ac可以拼接成aac,但ab和ca不能拼接在一起,根據題目ab和bc拼接成的abc也不行)看了一遍問題覺得這是一個概率題,刷了回答回來再看問題還是概率題。是我沒看懂么?
題目看了兩遍沒看懂的覺得更羞恥 , 悲傷
好像leetcode46題
就是求某個字元串中是否包含連續不同的三個字元。
這個題目我只有80%的通過率,沒明白是什麼原因!我是按上面的遞推公式計算的
推薦閱讀:
※面試會出哪些經典演算法題?
※如何通過自己編程為瀏覽知乎增加一些比較小眾的功能?
※零基礎學計算機?
※1950x 和7980xe 究竟有多少不同?
※人類為什麼要發明電腦硬碟燈?