CodeTop整理-字符串篇

目录

72. 编辑距离

3. 无重复字符的最长子串

5. 最长回文子串

20. 有效的括号

76. 最小覆盖子串

43. 字符串相乘

8. 字符串转换整数 (atoi)

22. 括号生成

14. 最长公共前缀

32. 最长有效括号

227. 基本计算器 II

151. 翻转字符串里的单词

93. 复原IP地址

632. 最小区间

415. 字符串相加

49. 字母异位词分组

10. 正则表达式匹配

17. 电话号码的字母组合

44. 通配符匹配

179. 最大数

208. 实现 Trie (前缀树)

395. 至少有 K 个重复字符的最长子串

567. 字符串的排列

516. 最长回文子序列

1143. 最长公共子序列

692. 前K个高频单词

394. 字符串解码


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值