两个字符串
目錄
(字符串的匹配)
- 正則化表達式匹配【含通配符】
- 正則化(數字字母)匹配【if re.search('^[0-9a-zA-Z]+$',ss): return True】
- 字符串匹配問題、贖金信(一個字符串字母是不是都在另一個字符串中)
- 同構字符串
- 單詞模式
- 查找和替換模式
- 判斷字符串A是否包含字符串B【字典實現】
- 重復子字符串
- 判斷兩個字符串是否互為旋轉詞
- 判斷兩個字符串是否互為變形詞
- 判斷兩個字符串是否為換位字符串(python)
- 數組中兩個字符串的最小距離【兩個位置變量】
- 求字符串的編輯距離(python)【動態規劃】
- 兩個字符串的最長公共子序列
- 兩個字符最長公共子串(python)
- 特殊等價字符串組
- 拼接所有字符串產生字典順序最小的大寫字符串
- 字符串的字典序最長子序列
- 按照給定的字母序列對字符數組排序(python)
- 數組中詞典中最長的字符串
- 刪除字符串重復的字母,返回字典序最小的一個
- 求兩個絕對路徑的相對路徑(python)
- 如何查找到目標詞的最短鏈長度(python)
- 找到由其他單詞組成的最長單詞(python)
- 字典樹(前綴樹)的實現
?
一、題目:正則化表達式匹配【含通配符】
給定一個正則字符串p,一個字符串s。要求驗證s和p是否能匹配。
特別的,正則字符串中僅由兩個特殊字符:'.'表示任意的單個字符,'*'表示其前方緊鄰元素連續出現0個或者更多個。要求匹配需要覆蓋整個輸入字符串,而不是部分的匹配。
s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字符 . 和 *。
思路:動態規劃:
狀態轉移數組 f [i] [j] 表示利用 p 的前 i 個字符匹配 s 的前 j 個字符的匹配結果(成功為true,失敗為false)。
邊界:
-
- dp[0][0] = True,s和p都是空格。
- i = 0,只有p為這種情況 p = ‘a*b*c*'才能True,別的都為False。
??????? for i in range(1,len(p)+1):???????????
if p[i-1] == '*': if i >= 2:
dp[0][i] = dp[0][i-2]
-
- j = 0,全部為False。即p為空,都False。
非邊界:
如果s[i] == p[j] 或者?p[j] == '.':【如果s的最后一位和p的最后一位相同,則只需要判斷前面的】
dp[i][j] = dp[i - 1][j - 1]
如果p[j] == '*':【dp[i][j-2]:*前面一位為0個即可,Sx~P】【dp[i][j-1]:*前面一位為1個,Sx~Pz】【dp[i-1][j]:*匹配x(x==z或者z=='.'), S~Pzy】
dp[i][j] = dp[i][j-2] || dp[i][j-1] || (dp[i-1][j] and (s[i-1]==p[j-2] or p[j-2]=='.'))
解釋:
對于s和p,設各個最后一個字符為x, y,p的倒數第二字符為z,除此外前面字符設為S,P,則:
s = Sx
p = Pzy
-
- 如果x == y或y == '.',則如果S和Pz匹配,則s和p匹配,因為最后兩字字母是匹配的。這就縮減了問題規模。
- 而對于y ==? '*'的情況,需要考慮z:
? ? 如果x != z,則只有在s和P匹配的情況下,s和p才匹配。
? ? 如果x == z,設匹配符號為~吧,方便,則如果S~Pzy,Sx~P,Sx~Pz,【S~P,S~Pz也匹配】都可得出s和p匹配。
?代碼:
def isMatch(self, s, p):""":type s: str:type p: str:rtype: bool"""dp = [[False] * (len(p) + 1) for i in range(len(s) + 1)]dp[0][0] = Truefor i in range(1,len(p)+1):if p[i-1] == '*':if i >= 2:dp[0][i] = dp[0][i-2]for i in range(1,len(s)+1):for j in range(1,len(p)+1):if p[j-1]=='.' or s[i-1] == p[j-1]:dp[i][j] = dp[i-1][j-1]elif p[j-1]=='*':dp[i][j] = dp[i][j-2] or dp[i][j-1] or (dp[i-1][j] and (s[i-1]==p[j-2] or p[j-2]=='.'))return dp[len(s)][len(p)]
?
?
一、題目:同構字符串
給定兩個字符串?s?和?t,判斷它們是否是同構的。
如果?s?中的字符可以被替換得到?t?,那么這兩個字符串是同構的。
所有出現的字符都必須用另一個字符替換,同時保留字符的順序。兩個字符不能映射到同一個字符上,但字符可以映射自己本身。
示例 1:
輸入: s = "egg", t = "add" 輸出: true示例 2:
輸入: s = "foo", t = "bar" 輸出: false示例 3:
輸入: s = "paper", t = "title" 輸出: true說明:
你可以假設?s?和 t 具有相同的長度。
?
代碼:
def isIsomorphic(self, s, t):return len(set(zip(s,t))) == len(set(s)) == len(set(t))?
二、題目:單詞模式:
給定一種 pattern(模式)?和一個字符串?str?,判斷 str 是否遵循相同的模式。
這里的遵循指完全匹配,例如,?pattern?里的每個字母和字符串?str?中的每個非空單詞之間存在著雙向連接的對應模式。
示例1:
輸入: pattern = "abba", str = "dog cat cat dog" 輸出: true示例 2:
輸入:pattern = "abba", str = "dog cat cat fish" 輸出: false示例 3:
輸入: pattern = "aaaa", str = "dog cat cat dog" 輸出: false示例?4:
輸入: pattern = "abba", str = "dog dog dog dog" 輸出: false說明:
你可以假設?pattern?只包含小寫字母,?str?包含了由單個空格分隔的小寫字母。? ??
代碼:
def wordPattern(self, pattern, str):""":type pattern: str:type str: str:rtype: bool"""a = str.split(" ")if len(pattern) != len(a):return Falsereturn len(set(zip(a,pattern))) == len(set(pattern)) == len(set(a))?三、題目:查找和替換模式
你有一個單詞列表?words?和一個模式??pattern,你想知道 words 中的哪些單詞與模式匹配。
如果存在字母的排列 p?,使得將模式中的每個字母 x 替換為 p(x) 之后,我們就得到了所需的單詞,那么單詞與模式是匹配的。
(回想一下,字母的排列是從字母到字母的雙射:每個字母映射到另一個字母,沒有兩個字母映射到同一個字母。)
返回 words 中與給定模式匹配的單詞列表。
你可以按任何順序返回答案。
?
示例:
輸入:words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb" 輸出:["mee","aqq"] 解釋: "mee" 與模式匹配,因為存在排列 {a -> m, b -> e, ...}。 "ccc" 與模式不匹配,因為 {a -> c, b -> c, ...} 不是排列。 因為 a 和 b 映射到同一個字母。?
提示:
- 1 <= words.length <= 50
- 1 <= pattern.length = words[i].length?<= 20
思路:時間O(n2)
?
對每個單詞判斷其與相應模式是否匹配,匹配則輸出。
判斷是否匹配函數strMatch,由于題目已知單詞長度相同,只需判斷在相同的位置,兩個單詞要有相同的相等或者不等關系即可。
代碼:
def findAndReplacePattern(self, words, pattern):""":type words: List[str]:type pattern: str:rtype: List[str]"""if not words or not pattern:return []def isSamePattern(s1,s2):for i in range(len(s1)):for j in range(i+1,len(s1)):if s1[i] == s1[j] and s2[i] != s2[j]:return Falseelif s2[i] == s2[j] and s1[i] != s1[j]:return Falsereturn Truei = 0while i < len(words):if isSamePattern(words[i],pattern):i += 1else:del words[i]return words?
一、重復子字符串
給定一個非空的字符串,判斷它是否可以由它的一個子串重復多次構成。給定的字符串只含有小寫英文字母,并且長度不超過10000。
示例 1:
輸入: "abab"輸出: True解釋: 可由子字符串 "ab" 重復兩次構成。示例 2:
輸入: "aba"輸出: False示例 3:
輸入: "abcabcabcabc"輸出: True解釋: 可由子字符串 "abc" 重復四次構成。 (或者子字符串 "abcabc" 重復兩次構成。)代碼:
def repeatedSubstringPattern(self, s):""":type s: str:rtype: bool"""if not s:return Falsess = (s + s)[1:-1]return ss.find(s)!=-1二、判斷兩個字符串是否互為旋轉詞
如果一個字符串str,把字符串str前面任意的部分挪到后面形成的字符串叫做str的旋轉詞。
如str="12345",str的旋轉詞有"12345"、"23451"、"34512"、"45123"、"51234"。
給定兩個字符串a和b,請判斷a和b是否互為旋轉詞。
舉例:
a="cdab",b="abcd",返回true;
a="1ab2",b="ab12",返回false;
a="2ab1",b="ab12",返回true。
要求:
如果a和b長度不一樣,那么a和b必然不互為旋轉詞,可以直接返回false。
當a和b長度一樣,都為N時,要求解法的時間復雜度為O(N)。
思路:
將兩個b拼接在一起賦值給c,查看c中是否包含字符串a,若包含,則返回true;否則返回false。
代碼:
def isRotation(a,b):if len(a) != len(b):return Falsec = b+breturn (a in c)a = 'cdab' b = 'abcd' isRotation(a,b)三、題目:互為變形詞
題目:給定兩個字符串str1和str2,如果str1和str2中出現的字符種類一樣且每種字符出現的次數也一樣,則str1和str2互為變形詞。
請實現函數判斷兩個字符串是否互為變形詞。
舉例:
str1="123", str2="231", 返回true;
str1="123", str2="2331",返回false。
思路:
1.?首先比較兩個字符串的長度,長度不同肯定是false。
2.?如果長度相同,新建一個字典,用以存儲每個字符出現次數。
3. 遍歷str1,在str1 中出現一次就加1,遍歷str2,在str2 中出現一次就減1,最后遍歷完str2沒有出現負值,就返回true。
代碼:
from collections import Counter def IsDeformation(str1,str2):if not str1 or not str2 or len(str1) != len(str2):return Falsecountstr1 = Counter(str1)for s2 in str2:if s2 in countstr1:countstr1[s2] -= 1if countstr1[s2] < 0:return Falseelse:return Falsereturn True str1 = '1234' str2 = '2313' IsDeformation(str1,str2)?
一、數組中兩個字符串的最小距離
思路:兩個變量分別更新str1和str2的位置,res記錄兩個變量差的最小值。
代碼:
import sys def minDistance(strs,str1,str2):if not strs or not str1 or not str2:return -1if str1 == str2:return 0last1 , last2 , res = -1 , -1 , sys.maxsizefor i in range(len(strs)):if strs[i] == str1:if last2 != -1:res = min(res,i - last2)last1 = iif strs[i] == str2:if last1 != -1:res = min(res,i - last1)last2 = ireturn res if res != sys.maxsize else -1 strs = ['3','1','3','3','3','2','3','1'] str1 = '1' str2 = '2' minDistance(strs,str1,str2)?
二、題目:最小編輯代價
給定兩個字符串str1和str2,再給定三個整數ic,dc,rc,分別代表插入、刪除、替換一個字符的代價,返回將str1編輯成str2的最小代價。
舉例:
str1="abc"?? str2="adc"? ic=5??? dc=3?? rc=2,從"abc"編輯到"adc"把b替換成d代價最小,為2;
str1="abc"?? str2="adc"? ic=5??? dc=3?? rc=10,從"abc"編輯到"adc",先刪除b再插入d代價最小,為8;
思路:動態規劃:時間O(M*N),空間O(M*N)
動態規劃表:dp[i][j]表示str1[0......i-1]編輯成str2[0......j-1]的最小編輯代價,dp大小為(M+1)*(N+1)是為了從空串開始計算,即dp[0][0]表示空串編輯到空串的最小編輯代價。
狀態方程:- 初始化:
dp[0][0] = 0
dp[0][j] = j * len(s2)
dp[i][0] = i * len(s1)
- dp[i][j] = min( dp[i][j-1]+ic ,?dc+dp[i-1][j] ,?dp[i-1][j-1] + rc 【如果str1[i-1]==str2[j-1],rc = rc,否則,rc = 0】)
2.求第一行dp[0][j],空串編輯成str2[0....j-1],則dp[0][j]=ic*j;
3.求第一列dp[i][0],str1[0......i-1]編輯成空串,則dp[i][0]=dc*i;
4.求dp[i][j],即str1[0....i-1]編輯成str2[0.....j-1],三種可能的途徑:
<1>str1[0....i-1]先編輯成str2[0.....j-2],再由str2[0.....j-2]插入到str2[0.....j-1],即 dp[i][j-1] + ic;
<2>str1[0....i-1]先編輯成str1[0.....i-2],再由str1[0.....i-2]刪除到str2[0.....j-1],即 dp[i-1][j] + dc;
<3>如果str1[i-1]==str2[j-1],則 dp[i][j] = dp[i-1][j-1];
?????? 如果str1[i-1]!=str2[j-1],則 dp[i][j] = dp[i-1][j-1] + rc; 最后比較三種途徑的最小值,即dp[i][j]的值。
?
代碼:
def mincost(s1,s2,ic,dc,rc):m , n = len(s1) , len(s2)if not s1:return n*icif not s2:return m*dcdp = [[0] * (n+1) for i in range(m+1)]for i in range(1,n + 1):dp[0][i] = ic * ifor j in range(1,m + 1):dp[j][0] = dc * jfor i in range(1,m+1):for j in range(1,n+1):if s1[i-1] == s2[j-1]:dp[i][j] = dp[i-1][j-1]else:dp[i][j] = dp[i-1][j-1] + rcdp[i][j] = min( dp[i][j] , dp[i-1][j] + dc , dp[i][j-1] + ic)return dp[-1][-1] s1 = 'ab12cd3' s2 = 'abcdf' ic , dc , rc = 5,3,2 mincost(s1,s2,ic,dc,rc)?
三、題目:最長公共子序列:
給定兩個字符串,求解這兩個字符串的最長公共子序列(Longest Common Sequence)。比如字符串L:BDCABA;字符串S:ABCBDAB
則這兩個字符串的最長公共子序列長度為4,最長公共子序列是:BCBA
思路:動態規劃:時間O(n * m),空間O(n * m)
創建 DP數組C[i][j]:表示子字符串L【:i】和子字符串S【:j】的最長公共子序列個數。
狀態方程:
個數代碼:
def LCS(L,S):if not L or not S:return ""dp = [[0] * (len(L)+1) for i in range(len(S)+1)]for i in range(len(S)+1):for j in range(len(L)+1):if i == 0 or j == 0:dp[i][j] = 0else:if L[j-1] == S[i-1]:dp[i][j] = dp[i-1][j-1] + 1else:dp[i][j] = max(dp[i-1][j],dp[i][j-1])return dp[-1][-1] L = 'BDCABA' S = 'ABCBDAB' LCS(L,S)最長子序列代碼:設置一個標志
def LCS(L,S):if not L or not S:return ""res = ''dp = [[0] * (len(L)+1) for i in range(len(S)+1)]flag = [['left'] * (len(L)+1) for i in range(len(S)+1)]for i in range(len(S)+1):for j in range(len(L)+1):if i == 0 or j == 0:dp[i][j] = 0flag [i][j] = '0'else:if L[j-1] == S[i-1]:dp[i][j] = dp[i-1][j-1] + 1flag[i][j] = 'ok'else:dp[i][j] = max(dp[i-1][j],dp[i][j-1])flag[i][j] = 'up' if dp[i][j] == dp[i-1][j] else 'left'return dp[-1][-1],flag def printres(flag,L,S):m = len(flag)n = len(flag[0])res = ''i , j = m-1 , n-1while i > 0 and j > 0:if flag[i][j] == 'ok':res += L[j-1]i -= 1j -= 1elif flag[i][j] == 'left':j -= 1elif flag[i][j] == 'up':i -= 1return res[::-1] L = 'BDCABA' S = 'ABCBDAB' num,flag = LCS(L,S) res = printres(flag,L,S)?
四、題目:最長公共子串
找出兩個字符串最長連續的公共字符串,如兩個母串cnblogs和belong,最長公共子串為lo
思路:動態規劃:時間O(N*M),空間O(N*M)
將二維數組c[i][j]用來記錄具有這樣特點的子串——結尾同時也為子串x1x2?xi與y1y2?yj的結尾的長度。
代碼:
def lcs(s1,s2):if not s1 or not s2:return 0c = [[0] * len(s2) for i in range(len(s1))]result = 0for i in range(len(s1)):for j in range(len(s2)):if i == 0 or j == 0:c[i][j] = 0else:if s1[i-1] == s2[j-1]:c[i][j] = c[i-1][j-1] + 1result = max(c[i][j],result)else:c[i][j] = 0return result s1 = 'cnblogs' s2 ='belong' lcs(s1,s2)?
六、題目:字符串的字典序最長子序列
對于字符串a和b,如果移除字符串a中的一些字母(可以全部移除,也可以一個都不移除)就能夠得到字符串b,則b為a的子序列。例如,‘heo'為'hello'的子序列,’le'不是。
對于給定的一個字符串s,請計算出s的字典序最大的子序列。
輸入:輸入包括一行,一個字符串s,字符串s長度length(1<=length<=50),s中每個字符串都是小寫字母
輸出:輸出字符串,即s的字典序最大的子序列。
例如:‘test'輸出:’tt' ? ? ? ? ?? 'string' 輸出 ‘trng' ? ? ?? 'bike'輸出'ke'
解法1:逆序排序,輸出原來的索引值,保留上升的索引值,輸出原來字符串對應索引值的子序列。
?
如:s='test',排序之后,s='ttse',索引應該是(0,3,2,1),0到3是升序,到2,1是降序,輸出:(0,3)對應的(’tt')再如:s='string',排序:s='tsrnig',索引(1,0,2,4,3,5)輸出:(1,2,4,5)對應的(‘trng') def Sublist(s):'''type(s)=string'''value_s=list(s)key_s=range(len(s))dic=dict(zip(key_s,value_s)) #字典逆序排序sort_dic=sorted(dic.items(),key=lambda x:x[1],reverse=True)key=[]value=[]for item in sort_dic:key.append(item[0])value.append(item[1]) #獲得逆序后的索引值cur=key[0]k=0for i in range(len(key)):if key[i-k]>=cur:cur=key[i-k]else:del key[i-k]k+=1 #返回對應索引的原字符串子序列res=[]for i in key:res.append(value_s[i])return str(res)
解法2:逆向查找字符串,若前面的字符比后面一個大,則保留前面的字符,否則把它刪除。
def Subdic(s1):s=list(s1)s.reverse()k=0for i in range(len(s)-1):if s[i-k]>s[i+1-k]:del s[i+1-k]k+=1s.reverse()return str(s)?
五、拼接所有字符串產生字典順序最小的大寫字符串
思路:排序本身時間O(NlogN)
假設兩個字符分別是a,b。a和b拼起來的字符串表示為a.b,那么如果a.b的字典順序小于b.a,就把a放在前面,否則把b放在前面。每兩兩字符之間都按照這個標準進行比較,以此標準排序后,最后串起來的結果就是正確答案。
如 ‘b' , 'ba',’b'和‘ba'排序后,’ba'應與'b'位置交換,‘ba’在前,‘b’在后。
代碼:cmp_to_key是因為python3中沒有cmp這種用法,取代的。
def lowestString(chas):if chas == None or len(chas) == 0:return ""from functools import cmp_to_keychas = sorted(chas, key=cmp_to_key(lambda x,y: 1 if x+y > y+x else -1))return ''.join(chas) chas = ['b','ba','abc','dba'] lowestString(chas)七、按照給定的字母序列對字符數組排序(python)
思路1:采用字典存儲規則:按照規則兩兩比較字符串
代碼:
1 from functools import cmp_to_key 2 3 4 def camp(s1, s2, dic): 5 m, n = len(s1), len(s2) 6 i, j = 0, 0 7 while i < m and j < n: 8 tmp1, tmp2 = list(s1)[i], list(s2)[j] 9 if tmp1 not in dic: 10 dic[tmp1] = -1 11 if tmp2 not in dic: 12 dic[tmp2] = -1 13 if dic[tmp1] > dic[tmp2]: 14 return 1 15 elif dic[tmp1] < dic[tmp2]: 16 return -1 17 else: 18 i += 1 19 j += 1 20 if i == len1: 21 return 1 22 else: 23 return -1 24 25 26 def compare(arr): 27 dic = {'d': 0, 'g': 1, 'e': 2, 'c': 3, 'f': 4, 'b': 5, 'o': 6, 'a': 7} 28 if len(arr) <= 1: 29 return arr 30 res = sorted(arr, key=cmp_to_key(lambda x, y: camp(x, y, dic))) 31 32 return res 33 34 35 arr = ['bed', 'dog', 'dear', 'eye'] 36 print(compare(arr))?
?
八、題目:詞典中最長的子序列
給出一個字符串數組words組成的一本英語詞典。從中找出最長的一個單詞,該單詞是由words詞典中其他單詞逐步添加一個字母組成。若其中有多個可行的答案,則返回答案中字典序最小的單詞。
若無答案,則返回空字符串。
示例 1:
輸入: words = ["w","wo","wor","worl", "world"] 輸出: "world" 解釋: 單詞"world"可由"w", "wo", "wor", 和 "worl"添加一個字母組成。示例 2:
輸入: words = ["a", "banana", "app", "appl", "ap", "apply", "apple"] 輸出: "apple" 解釋: "apply"和"apple"都能由詞典中的單詞組成。但是"apple"得字典序小于"apply"。注意:
- 所有輸入的字符串都只包含小寫字母。
- words數組長度范圍為[1,1000]。
- words[i]的長度范圍為[1,30]。
2、思路:
排序列表,從后往前遍歷排序的列表,再遍歷單詞的子序列在不在列表中,若全在則把該單詞加進結果列表中。最后找出結果列表中最長的單詞,若多個單詞長度一樣,則選擇字典序最前的。
代碼1:
def longestWord(self, words):""":type words: List[str]:rtype: str"""res=[]if not words:return ""else:newWords=sorted(words) for i in range(0,len(newWords)):last_word=newWords[len(newWords)-1-i]while last_word in newWords:last_word=last_word[:-1]if not last_word:res.append(newWords[len(newWords)-1-i]) result=sorted(res,key=lambda x:len(x),reverse=True)flag=0for i in range(0,len(result)):if i==len(result)-1 or len(result[i])!=len(result[i+1]):flag=ibreakelse:continuereturn "" if not result else result[i]代碼2:
def longestWord(self, words):ans = ""wordset = set(words)for word in words:if len(word) > len(ans) or len(word) == len(ans) and word < ans:if all(word[:k] in wordset for k in range(1, len(word))):ans = wordreturn ans?
?題目:刪除字符串重復的字母,返回字典序最小的一個
?思路:采用一個棧stack存字母、采用一個count字典數字符串的字符個數、采用一個visited字典表示該字母是否已經確定。
class Solution(object):def removeDuplicateLetters(self, s):""":type s: str:rtype: str"""count = collections.Counter(s)stack = []visited = collections.defaultdict(bool)for c in s:count[c] -= 1if visited[c]:continuewhile stack and count[stack[-1]] and stack[-1] > c:visited[stack[-1]] = Falsestack.pop()visited[c] = Truestack.append(c)return "".join(stack)?
?
?
轉載于:https://www.cnblogs.com/Lee-yl/p/10466426.html
總結
- 上一篇: Golang中使用kafka
- 下一篇: 《剑指offer》第九题(用两个栈实现队