目录
72. 编辑距离
# 72. 编辑距离
# 给你两个单词word1 和word2, 请返回将word1转换成word2 所使用的最少操作数 。
# 你可以对一个单词进行如下三种操作:
#
# 插入一个字符
# 删除一个字符
# 替换一个字符
#
# 输入:word1 = "horse", word2 = "ros"
# 输出:3
# 解释:
# horse -> rorse (将 'h' 替换为 'r')
# rorse -> rose (删除 'r')
# rose -> ros (删除 'e')
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m=len(word1)
n=len(word2)
dp=[[0]*(n+1) for i in range(m+1)]
for i in range(1,m+1):
dp[i][0]=i
for j in range(1,n+1):
dp[0][j]=j
for i in range(1,m+1):
for j in range(1,n+1):
if word1[i-1]==word2[j-1]:
dp[i][j]=dp[i-1][j-1]
else:
dp[i][j]=min(dp[i-1][j],dp[i][j-1],dp[i-1][j-1])+1
return dp[-1][-1]
3. 无重复字符的最长子串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其
长度为 3。
class Solution:
def lengthOfLongestSubstring(self, s):
from collections import defaultdict
h=defaultdict(int)
n=len(s)
l,r,cnt,max_len=0,0,0,0 #cnt记录重复元素的个数,max_len记录最大元素的长度,[l,r]滑动窗口边界
while r<n:
if(h[s[r]]>0):
cnt+=1
h[s[r]]+=1
r+=1
while(cnt>0):
if(h[s[l]]>1): #去掉其中重复的元素,只会有一个元素重复
cnt-=1
h[s[l]]-=1
l+=1
max_len=max(max_len,r-l)
return max_len
5. 最长回文子串
# 5. 最长回文子串
# 给你一个字符串 s,找到 s 中最长的回文子串。
#
# 输入:s = "babad"
# 输出:"bab"
# 解释:"aba" 同样是符合题意的答案。
class Solution:
def longestPalindrome(self, s: str) -> str:
def find(l, r):
while (l >= 0 and r < len(s) and s[l] == s[r]):
l -= 1
r += 1
return l, r
ans = ''
for i in range(len(s)):
l1, r1 = find(i, i)
l, r = l1, r1
if i > 0:
l2, r2 = find(i - 1, i)
if (r2 - l2 > r1 - l1):
l, r = l2, r2
if (len(ans) < r - l - 1):
ans = s[l + 1:r]
return ans
20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
输入:s = "()" 输出:true
class Solution:
def isValid(self, s: str) -> bool:
st=[]
for c in s:
if c in '([{':
st.append(c)
else:
if not st:
return False
t=st.pop()
if c==')' and t!='(' :
return False
if c==']' and t!='[' :
return False
if c=='}' and t!='{' :
return False
if st:
return False
return True
76. 最小覆盖子串
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意:
- 对于
t
中重复字符,我们寻找的子字符串中该字符数量必须不少于t
中该字符数量。 - 如果
s
中存在这样的子串,我们保证它是唯一的答案。
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。
class Solution:
def minWindow(self, s, t):
from collections import defaultdict
l,r,cnt,n,h=0,0,len(t),len(s),defaultdict(int)
res=""
for c in t:
h[c]+=1
while(r<n):
if(h[s[r]]>0):
cnt-=1
h[s[r]]-=1
r += 1
while(cnt==0):
cur=s[l: r]
if(res=="" or len(res)>len(cur)):
res=cur
if(h[s[l]]==0):
cnt+=1
h[s[l]]+=1
l+=1
return res
43. 字符串相乘
# 43. 字符串相乘
# 给定两个以字符串形式表示的非负整数num1和num2,返回num1和num2的乘积,它们的乘积也表示为字符串形式。
# 注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。
# 输入: num1 = "2", num2 = "3"
# 输出: "6"
# class Solution: #这个方法通过有点诧异
# def multiply(self, num1: str, num2: str) -> str:
# m,n=len(num1),len(num2)
# ans=0
# for i in range(m-1,-1,-1):
# t=0
# for j in range(n-1,-1,-1):
# t+=int(num1[i])*int(num2[j])*(10**(n-1-j))
# t=t*(10**(m-1-i))
# # print(i,num1[i],t)
# ans+=t
# return str(ans)
class Solution: #这个方法通过有点诧异
def multiply(self, num1: str, num2: str) -> str:
def addArr(a,b):
m,n=len(a),len(b)
carry,add=0,0
i=n-1
j=m-1
while i>=0 and j>=0:
t=a[j]+b[i]+carry
carry,add=t//10,t%10
a[j]=add
i-=1
j-=1
while j>=0:
t = a[j]+ carry
carry, add = t // 10, t % 10
a[j] = add
j-=1
m,n=len(num1),len(num2)
ans=[0]*(m+n)
for i in range(m-1,-1,-1):
cur=[0]*(m-1-i)
carry=0
add=0
for j in range(n-1,-1,-1):
t=int(num1[i])*int(num2[j])+carry
carry=t//10
add=t%10
cur.append(add)
if(carry>0):
cur.append(carry)
addArr(ans,cur[::-1])
print(i, cur[::-1],ans)
# print(i,num1[i],t)
while len(ans)>1 and ans[0]==0 :
ans.pop(0)
return str(''.join(map(str,ans)))
s=Solution()
# num1='2'
# num2='6'
# num1 = "123"
# num2 = "456"
num1 = "0"
num2 = "0"
r=s.multiply(num1,num2)
print(r)
8. 字符串转换整数 (atoi)
# 8. 字符串转换整数 (atoi)
# 请你来实现一个myAtoi(string s)函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。
# 函数myAtoi(string s) 的算法如下:
# 读入字符串并丢弃无用的前导空格
# 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
# 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
# 将前面步骤读入的这些数字转换为整数(即,"123" -> 123, "0032" -> 32)。如果没有读入数字,则整数为 0 。必要时更改符号(从步骤 2 开始)。
# 如果整数数超过 32 位有符号整数范围 [−231, 231− 1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 −231 ,大于 231− 1 的整数应该被固定为 231− 1 。
# 返回整数作为最终结果。
# 注意:
# 本题中的空白字符只包括空格字符 ' ' 。
# 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。
class Solution:
def myAtoi(self, s: str) -> int:
i=0
l=len(s)
flag=1
num=0
while(i<l):
if i==0:
while(i<l and s[i]==' '):
i+=1
if i<l and s[i] in '-+':
if s[i]=='-':
flag=-1
i+=1
if i<l and s[i]>='0' and s[i]<='9':
num=int(s[i])
while(i+1<l and s[i+1]>='0' and s[i+1]<='9'):
num=10*num+int(s[i+1])
i=i+1
else:
break
i+=1
ans=flag*num
if ans<=-1*(2**31):
ans=-1*(2**31)
if ans>=(2**31)-1:
ans=(2**31)-1
return ans
# s1="42"
# s1=" -42"
# s1="4193 with words"
# s1='+'
s1=" "
s=Solution()
r=s.myAtoi(s1)
print(r)
22. 括号生成
数字 n
代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
输入:n = 3 输出:["((()))","(()())","(())()","()(())","()()()"]
from typing import List
# 这种方法超时了
# class Solution:
# def generateParenthesis(self, n: int) -> List[str]:
# res=[]
# t=[]
# s=['(',')']*n
# valid=[False]*2*n
# def is_valid(s1): #判断有效括号
# b=0
# for c in s1:
# if c=='(':
# b+=1
# else:
# b-=1
# if b<0:
# return False
# return b==0
#
# def dfs(h): #排列组合
# if(h==2*n):
# s1=''.join(t)
# if(is_valid(s1)):
# res.append(s1)
# return
#
# for i in range(len(s)):
# if not valid[i] :
# valid[i]=True
# t.append(s[i])
# dfs(h+1)
# t.pop()
# valid[i] = False
# dfs(0)
# return list(set(res))
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
res=[]
t=[]
def is_valid(s1): #判断有效括号
b=0
for c in s1:
if c=='(':
b+=1
else:
b-=1
if b<0:
return False
return b==0
def dfs(h): #排列组合
if(h==2*n):
s1=''.join(t)
if(is_valid(s1)):
res.append(s1)
return
for i in '()':
t.append(i)
dfs(h+1)
t.pop()
dfs(0)
return list(set(res))
s=Solution()
r=s.generateParenthesis(3)
print(r)
14. 最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 ""
。
输入:strs = ["flower","flow","flight"] 输出:"fl"
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
ans=""
min_len=float("inf")
for s in strs:
len_s=len(s)
if len_s<min_len:
ans=s
min_len=len_s
for i in range(min_len-1,-1,-1):
for s in strs:
if s[i]!=ans[i]:
ans=ans[0:i]
break
return ans
32. 最长有效括号
# 32. 最长有效括号
# 给你一个只包含 '(' 和 ')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。
# 输入:s = "(()"
# 输出:2
# 解释:最长有效括号子串是 "()"
# 动归
# class Solution:
# def longestValidParentheses(self, s: str) -> int:
# n=len(s)
# if n<=0:
# return 0
# dp=[0]*(n+1)
# for i in range(2,n+1):
# if (s[i-1]==')'):
# print(i,i-1,i-2,i-1-dp[i-1]-1)
# if(s[i-2]=='('):
# dp[i]=max(dp[i],dp[i-2]+2)
# if(i-1-dp[i-1]-1>=0 and s[i-1-dp[i-1]-1]=='('):
# dp[i]=max(dp[i],dp[i-1]+dp[i-1-dp[i-1]-1]+2)
# print(dp)
# return max(dp)
#left ,right
# 动归
class Solution:
def longestValidParentheses(self, s: str) -> int:
n=len(s)
if n<=0:
return 0
ans =0
l,r,i=0,0,0
while(i<n):
if(s[i]=='('):
l+=1
else:
r+=1
if(l==r):
ans=max(ans,2*l)
elif(r>l):
l,r=0,0
i+=1
l,r,i=0,0,n-1
while(i>=0):
if (s[i] == '('):
l += 1
else:
r += 1
if (l == r):
ans = max(ans, 2 * l)
elif (l > r):
l, r = 0, 0
i-=1
return ans
# s1="(()"
# s1="()()"
# s1="()(())"
s1="(()))())("
s=Solution()
r=s.longestValidParentheses(s1)
print(r)
227. 基本计算器 II
给你一个字符串表达式 s
,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
输入:s = "3+2*2" 输出:7
class Solution:
def calculate(self, s: str) -> int:
num=0
ans=0
st=[]
preSign='+'
for i,c in enumerate(s):
if c in '0123456789':
num=10*num+int(c)
if c in '+-*/' or i==len(s)-1 :
print(num,c)
if preSign == '*':
t=st.pop()
num=t*num
st.append(num)
if preSign=='/':
t=st.pop()
num=int(t/num)
st.append(num)
if preSign=='+':
st.append(num)
if preSign=='-':
st.append(-num)
preSign=c
num=0
print(st)
while st:
ans+=st.pop()
return ans
151. 翻转字符串里的单词
class Solution:
def reverseWords(self, s: str) -> str:
st=s.split(' ')
st=[w for w in st if w!='']
st=st[::-1]
return ' '.join(st)
93. 复原IP地址
# 93. 复原 IP 地址
# 有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
#
# 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
# 给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
#
# 输入:s = "25525511135"
# 输出:["255.255.11.135","255.255.111.35"]
from typing import List
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
for c in s:
if not (c in '0123456789'):
return []
res=set()
t=[]
def is_valid(tmp):
for c in tmp:
if c.startswith('0') and len(c)>1:
return False
if int(c)<0 or int(c)>255:
return False
return True
def dfs(b,h):
if(h==4):
if(b!=len(s)):
return
if(is_valid(t)):
res.add('.'.join(t))
return
for i in range(b+1,len(s)+1):
t.append(s[b:i])
dfs(i,h+1)
t.pop()
dfs(0,0)
return list(res)
s1 = "25525511135"
s=Solution()
r=s.restoreIpAddresses(s1)
print(r)
class Solution:
def restoreIpAddresses(self, s: str) -> List[str]:
SEG_COUNT = 4
ans = list()
segments = [0] * SEG_COUNT
def dfs(segId: int, segStart: int):
# 如果找到了 4 段 IP 地址并且遍历完了字符串,那么就是一种答案
if segId == SEG_COUNT:
if segStart == len(s):
ipAddr = ".".join(str(seg) for seg in segments)
ans.append(ipAddr)
return
# 如果还没有找到 4 段 IP 地址就已经遍历完了字符串,那么提前回溯
if segStart == len(s):
return
# 由于不能有前导零,如果当前数字为 0,那么这一段 IP 地址只能为 0
if s[segStart] == "0":
segments[segId] = 0
dfs(segId + 1, segStart + 1)
# 一般情况,枚举每一种可能性并递归
addr = 0
for segEnd in range(segStart, len(s)):
addr = addr * 10 + (ord(s[segEnd]) - ord("0"))
if 0 < addr <= 0xFF:
segments[segId] = addr
dfs(segId + 1, segEnd + 1)
else:
break
dfs(0, 0)
return ans
632. 最小区间
你有 k 个 非递减排列 的整数列表。找到一个 最小 区间,使得 k 个列表中的每个列表至少有一个数包含在其中。
我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。
输入:nums = [[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
输出:[20,24]
解释:
列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。
列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。
列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。
# 1、合并数组并标识所属数组,(数值,组号)
# 2、用h记录每个组出现的次数,组编号为0,1,2;因而可以直接用数组存储
# 3、l,r滑动窗口遍历排序后的数组,当所有组号都在h中时,l前移,找到最小区间
class Solution:
def smallestRange(self, nums) :
ordered = sorted((j,i) for i,a in enumerate(nums) for j in a )
h=[0]*len(nums)
l,r=0,0
res=[ordered[0][0],ordered[-1][0]]
while r< len(ordered):
h[ordered[r][1]]+=1
if 0 not in h:
while h[ordered[l][1]]>1:
h[ordered[l][1]] -= 1
l+=1
if res[1]-res[0]>ordered[r][0]-ordered[l][0]:
res=[ordered[l][0],ordered[r][0]]
r += 1
return res
415. 字符串相加
class Solution:
def addStrings(self, num1: str, num2: str) -> str:
if len(num1)>len(num2):
return self.addStrings(num2,num1)
n1,n2=len(num1),len(num2)
c,a,i1,i2=0,0,n1-1,n2-1
st=[]
while i1>=0 and i2>=0:
a=int(num1[i1])+int(num2[i2])+c
c=a//10
a=a%10
st.append(a)
i1-=1
i2-=1
while i2>=0:
a=int(num2[i2])+c
c=a//10
a=a%10
st.append(a)
i2-=1
if c>0:
st.append(c)
st=st[::-1]
return ''.join(list(map(str,st)))
49. 字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
h={}
for s in strs:
s1=''.join(sorted(list(s)))
if s1 in h:
h[s1].append(s)
else:
h[s1]=[s]
ans=[]
for k in h.keys():
ans.append(h[k])
return ans
10. 正则表达式匹配
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
def match(i,j):
if(i<0):
return False
if(p[j]=='.'):
return True
if(s[i]==p[j]):
return True
return False
m=len(s)
n=len(p)
print(m,n)
flags=[[False]*(n+1) for i in range(m+1)] #记录flags[i][j]记录s[0:i-1]与p[0:j-1]的匹配情况
flags[0][0]=True #s,p均为空时,可以匹配
for i in range(1,m+1): #p为空时,s不为空时,不匹配 ;当s为空,p为x*时,可能匹配
flags[i][0]=False
for i in range(0,m+1):
for j in range(1,n+1):
if p[j-1]=='*': #'*'在p中只可能出现在[1:]的位置
flags[i][j]=flags[i][j] or flags[i][j-2]
if(match(i-1,j-2)):
flags[i][j]=flags[i][j] or flags[i-1][j]
else:
if(match(i-1,j-1)):
flags[i][j]=flags[i-1][j-1]
else:
flags[i][j]=False
print(flags)
return flags[m][n]
17. 电话号码的字母组合
给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
num_chars={
2:list("abc"),
3:list("def"),
4:list("ghi"),
5:list("jkl"),
6:list("mno"),
7:list("pqrs"),
8:list("tuv"),
9:list("wxyz")
}
def dfs(k):
if(len(path)==len(digits)):
print(path)
res.append(''.join(path[:]))
return
chars=num_chars[int(digits[k])]
for i in range(len(chars)):
path.append(chars[i])
dfs(k+1)
path.pop()
res=[]
path=[]
dfs(0)
return res
44. 通配符匹配
给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符序列(包括空字符序列)。
判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。
输入:s = "aa", p = "a" 输出:false 解释:"a" 无法匹配 "aa" 整个字符串。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
f=[[False]*(len(p)+1) for i in range(len(s)+1)]
f[0][0]=True
for j in range(1,len(p)+1):
if p[j-1]!='*':
break
f[0][j]=True
for i in range(1,len(s)+1):
for j in range(1,len(p)+1):
if s[i-1]==p[j-1] or p[j-1]=='?':
f[i][j]=f[i-1][j-1]
elif p[j-1]=='*':
f[i][j]=f[i][j-1] or f[i-1][j]
return f[-1][-1]
179. 最大数
给定一组非负整数 nums
,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
输入:nums=[10,2] 输出:"210"
class Solution:
def largestNumber(self, nums: List[int]) -> str:
nums=list(map(str,nums))
for i in range(len(nums)):
for j in range(i+1,len(nums)):
if(nums[i]+nums[j]<nums[j]+nums[i]):
nums[i],nums[j]=nums[j],nums[i]
s=''.join(nums)
if s.startswith('0'):
return '0'
return s
208. 实现 Trie (前缀树)
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:
Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
# 方案1参考网址
# https://leetcode.cn/problems/implement-trie-prefix-tree/solution/208-shi-xian-trie-qian-zhui-shu-bao-gua-insert-sea/
# class TrieNode:
# def __init__(self):
# self.path=0
# self.end=0
# self.next={}
# class Trie:
# def __init__(self):
# self.root=TrieNode()
# def insert(self, word: str) -> None:
# if not word or word=='':
# return None
# node=self.root
# for c in word:
# if c not in node.next:
# node.next[c]=TrieNode()
# node.path+=1
# node=node.next[c]
# node.end+=1
# def search(self, word: str) -> bool:
# if not word or word=='':
# return True
# node=self.root
# for c in word:
# if(c not in node.next):
# return False
# node=node.next[c]
# if node.end==0:
# return False
# return True
# def startsWith(self, prefix: str) -> bool:
# if not prefix or prefix=='':
# return True
# node=self.root
# for c in prefix:
# if(c not in node.next):
# return False
# node=node.next[c]
# return True
class TrieNode:
def __init__(self):
self.next=[None]*26
self.isEnd=False
class Trie:
def __init__(self):
self.root=TrieNode()
def insert(self, word: str) -> None:
if not word or word=='':
return None
node=self.root
for c in word:
idx=ord(c)-ord('a')
if not node.next[idx]:
node.next[idx]=TrieNode()
node=node.next[idx]
node.isEnd=True
def search(self, word: str) -> bool:
if not word or word=='':
return True
node=self.root
for c in word:
idx=ord(c)-ord('a')
if not node.next[idx]:
return False
node=node.next[idx]
if not node.isEnd:
return False
return True
def startsWith(self, prefix: str) -> bool:
if not prefix or prefix=='':
return True
node=self.root
for c in prefix:
idx=ord(c)-ord('a')
if not node.next[idx]:
return False
node=node.next[idx]
return True
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
395. 至少有 K 个重复字符的最长子串
给你一个字符串 s
和一个整数 k
,请你找出 s
中的最长子串, 要求该子串中的每一字符出现次数都不少于 k
。返回这一子串的长度。
输入:s = "aaabb", k = 3 输出:3 解释:最长子串为 "aaa" ,其中 'a' 重复了 3 次。
class Solution:
def longestSubstring(self, s: str, k: int) -> int:
from collections import defaultdict
h=defaultdict(int)
for c in s:
h[c]+=1
cnt=0
for c in h:
if(h[c]>=k):
cnt+=1
ans = 0
for n in range(1,27):
if(n>cnt):
break
t=defaultdict(int)
l,r=0,0
char_class,char_num=0,0
while(r<len(s)):
t[s[r]]+=1
if (t[s[r]]==1):
char_num+=1
char_class+=1
if(t[s[r]]==k):
char_num-=1
# print('$1',n,l,r,char_num,char_class,t)
while(char_class>n):
# print('#',l,t,char_class,char_num)
if(t[s[l]]==1):
char_class-=1
char_num -= 1
if(t[s[l]]==k):
char_num+=1
t[s[l]]-=1
l+=1
r+=1
# print('$2',n,l,r,char_num,char_class,t)
if(char_num==0):
# print('*',char_num,r,l,t)
ans=max(ans,r-l)
return ans
567. 字符串的排列
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
输入:s1 = "ab" s2 = "eidbaooo" 输出:true 解释:s2 包含 s1 的排列之一 ("ba").
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
from collections import defaultdict
h=defaultdict(int)
cnt=0
for c in s1:
h[c]+=1
cnt=len(h)
l,r=0,0
while(r<len(s2)):
h[s2[r]]-=1
if(h[s2[r]]==0):
cnt-=1
r+=1
# print (l,r,cnt,h)
while(l<r and cnt==0):
# print('#',l,r,cnt,h)
if(h[s2[l]]==0):
if(r-l==len(s1)):
return True
else:
cnt+=1
h[s2[l]]+=1
l+=1
return False
516. 最长回文子序列
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
输入:s = "bbbab" 输出:4 解释:一个可能的最长回文子序列为 "bbbb" 。
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
n=len(s)
dp=[[0]*n for i in range(n)] #dp[i][j] i<=k<=j的最长子串长度
for i in range(n-1,-1,-1):
dp[i][i]=1
for j in range(i+1,n):
if s[i]==s[j]:
dp[i][j]=dp[i+1][j-1]+2 #加上s[i]、s[j]首尾2个节点
else:
dp[i][j]=max(dp[i+1][j],dp[i][j-1]) #丢掉s[i]或s[j]后构成的最长回文串
return dp[0][n-1]
1143. 最长公共子序列
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
输入:text1 = "abcde", text2 = "ace" 输出:3 解释:最长公共子序列是 "ace" ,它的长度为 3 。
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m=len(text1)
n=len(text2)
dp=[[0]*(n+1) for i in range(m+1)]
for i in range(m+1):
dp[i][0]=0
for j in range(n+1):
dp[0][j]=0
for i in range(1,m+1):
for j in range(1,n+1):
if text1[i-1]==text2[j-1]:
dp[i][j]=dp[i-1][j-1]+1
else:
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
return dp[-1][-1]
692. 前K个高频单词
给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。
返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。
输入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
注意,按字母顺序 "i" 在 "love" 之前。
class Solution:
def topKFrequent(self, words: List[str], k: int) -> List[str]:
from collections import defaultdict
h=defaultdict(int)
for c in words:
h[c]+=1
res=sorted(h,key=lambda w:(-h[w],w))
return res[0:k]
394. 字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
输入:s = "3[a]2[bc]" 输出:"aaabcbc"
class Solution:
def decodeString(self, s: str) -> str:
ans=''
st=[]
num=0
for c in s:
if '0'<=c<='9':
num=10*num+int(c)
elif c=='[':
st.append([ans,num])
ans,num='',0
elif c==']':
last,k=st.pop()
ans=last+k*ans
else:
ans+=c
return ans