深信服筆試--遞歸用法


1、已知某一個字母序列,把序列中的字母按出現順序壓入一個棧,在入棧的任意過程中,允許棧中的字母出棧,求所有可能的出棧順序
思路:
遍歷序列中的每一個字母,先把當前字母入棧,這個時候,棧中肯定有字母,你可以選擇繼續遍歷序列,也可以在這個時候把棧中的字母一個一個出棧,
最后,遍歷完序列后,再把棧中的所有字母順序出棧,這樣子就可以得到所有合法的序列;
 1 #import itertools
 2 def GetAllSeq(input, i, stk, tmp, res):
 3     tmp1 = list(tmp) # 注意tmp1和stk是要回溯的,所以這兩者不能傳引用;而res是一直保留結果的,傳引用就對
 4     stk1 = list(stk)
 5     if i == len(input): # 結果記錄
 6         stk1 = stk1[::-1]
 7         tmp1.extend(stk1)
 8         res.append(tmp1)
 9         #print(res)
10         return
11     stk1.append(input[i]) # 先將當前字母入棧,然后后面選擇繼續遞歸入棧或者出棧
12     GetAllSeq(input, i+1, stk1, tmp1, res) #繼續遍歷
13     while stk1: # 一個個出棧
14         #tmp = []
15         tmp1.append(stk1[-1])
16         stk1.pop()
17         GetAllSeq(input, i+1, stk1, tmp1, res)
18 
19 
20 
21 input = 'abc'
22 res = []
23 stk = ''
24 tmp = ''
25 GetAllSeq(input, 0, stk, tmp, res)
26 
27 res = [''.join(x) for x in res]
28 # 法一
29 # res = list(set(res))
30 # res.sort()
31 
32 # 法二
33 #res = itertools.groupby(res)
34 
35 # 法三 dict去重並保留順序
36 # res = list(dict.fromkeys(res))
37 # print(res)

 

2、函數match檢查字符串str是否匹配模板pattern,匹配則返回0,否則返回-1。模板支持普通字符(a-z0-9A-Z)及通配符?和*。普通字符匹配該字符本身,?匹配任意一個字符,*匹配任意多個任意字符。

思路:使用遞歸回溯遍歷所有的情況

def match(str, pattern):
    str_len, pattern_len = len(str), len(pattern)
    if not str_len and not pattern_len:
        return 0
    if not str_len or not pattern_len:
        return -1
    if pattern[0] == '*': #如果是*則前者遞歸k個單位(k進行迭代遍歷取值),后者遞歸一個單位
        for i in range(len(str)):
            if match(str[i+1:], pattern[1:]) == 0: # 遞歸
                return 0
        return -1
    elif pattern[0] == '?': # 如果是?則兩者都遞歸一個單位
        return match(str[1:], pattern[1:])
    else:
        if pattern[0] == str[0]: # 如果是相同則兩者都遞歸一個單位
            return match(str[1:], pattern[1:])
        else:
            return -1

str = input()
pattern = input()
res = match(str, pattern)
print(res)

if res == 0:
    print('match')
elif res == -1:
    print('unmat

 

3、有K種顏色的小球(K<=10),每種小球有若干個,總數小於100個。

現在有一個小盒子,能放N個小球(N<=8),現在要從這些小球里挑出N個小球,放滿盒子。
想知道有哪些挑選方式。注:每種顏色的小球之間沒有差別。

請按數字遞增順序輸出挑選小球的所有方式。

如有3種顏色,每種顏色小球的個數分別為a:1,b:2,c:3,挑出3個小球的挑法有:
003,012,021,102,111,120

 

思路:遞歸回溯,my_dic, res, s都可變,s用來保存理想結果,注意s的現場恢復

# K, N = list(map(int, input().split()))
# def bfs(i, my_dic, cnt, res, s):
#     if i == K and cnt == N:
#         res.append(''.join(s))
#     elif i < K:
#         for use in range(my_dic[i]+1): # 迭代遞歸:先迭代整個串,然后再遞歸每個子集
#             if use <= N - cnt:
#                 s.append(str(use))
#                 bfs(i+1, my_dic, cnt+use, res, s)
#                 s.pop() #回溯
#             else:
#                 break
# my_dic = {}
# for i in range(K):
#     my_dic[i] = int(input())
# res = []
# bfs(0, my_dic, 0, res, [])
# for r in res:
#     print(r)

a = [0] * 11
ans = [0] * 11
def Print(k, ans):
    res = ''
    for i in range(k):
        res += str(ans[i])
    print(res)

def fun(i, n):
    if n == 0:
        Print(k, ans)
        return
    if n < 0 or k == i:
        return
    for j in range(a[i]+1):
        ans[i] = j
        fun(i+1, n-j)
    ans[i] = 0 #回溯

k,n = list(map(int, input().split()))
a = {}
for i in range(k):
    a[i] = int(input())
fun(0, n)

 

4、判斷所給的字符串是否由所給的詞典中的若干個詞組成。

如已知詞典["code", "sangfor", "org"]
則字符串"codesangfororg" 由上述詞典組成,
字符串"codesangforsangfororg" 也由上述詞典組成,
但字符串"sangforcom" 則不由上述詞典組成。

def wordbreak(s, WordDict):
    if not s or not len(s):
        return False
    dp = [False for i in range(len(s)+1)]
    dp[0] = True
    for i in range(1, len(s)+1): # 迭代遞歸:先迭代遍歷整個串,然后再對每個子串進行遞歸遍歷
        for j in range(i): 
            if dp[j] and (s[j:i] in WordDict):
                dp[i] = True
                break
    return dp[len(s)]

K = int(input())
WordDict = []
for i in range(K):
    WordDict.append(input())
s = input()

res = wordbreak(s, WordDict)
print(res)

 

5、總結

先看問題是否是求整體字符串中的可變長子集(起始點不確定),如果是則先迭代遍歷整個串,然后在遞歸每個子串,如3、4題;

如果是起始點確定的可變長子集,如2題,則可以不用迭代遍歷整個串,只需要遞歸遍歷子串就行。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM