Leetcode每日好多题:排序算法+字符串相关问题

目录

  • 第一章 红黑树和AVL树
  • 第二章 排序算法
    • 1、简单的排序
      • 冒泡排序
      • 选择排序
      • 插入排序
      • 希尔排序
    • 2、高级排序
      • 快速排序
      • 归并排序
    • 3、Leetcode 1122:数组的相对排序
    • 4、Leetcode 242:有效的字母异位词
    • 5、Leetcode 1244:力扣排行榜
    • 6、Leetcode 56:合并区间
    • 7、剑指Offer 51 数组中的逆序对
    • 8、Leetcode 491: 翻转对
  • 第三章 字符串
    • 1、Leetcode 709 转换成小写字母
    • 2、Leetcode 58:最后一个单词的长度
    • 3、Leetcode 771:宝石与石头
    • 4、剑指offer 50:第一个只出现一次的字符
    • 5、Leetcode 8:字符串转换整数
    • 6、Leetcode 14:最长公共前缀
    • 7、Leetcode 344:反转字符串
    • 8、Leetcode 541:反转字符串ii
    • 9、Leetcode 151:反转字符串里的单词
    • 10、Leetcode 557:反转字符串中的单词III
    • 11、Leetcode 917:仅仅反转字母
    • 12、Leetcode 242:有效的字母异位词重写
    • 13、Leetcode 49:字母异位词分组:
    • 14、Leetcode 438:找到字符串中的所有字母异位词
    • 15、Leetcode 1143:最长公共子序列重写
    • 16、Leetcode 125:验证回文串
    • 17、Leetcode 680:验证回文字符串ii
    • 18、Leetcode 5:最长回文子串
    • 19、Leetcode 72:编辑距离重写
    • 20、Leetcode 10:正则表达式匹配
    • 21、Leetcode 44:通配符匹配
    • 22、Leetcode 115:不同的子序列重写

第一章 红黑树和AVL树

树的旋转(当平衡因子不在-1,1,0中)
在这里插入图片描述
红黑树
在这里插入图片描述
在这里插入图片描述

第二章 排序算法

在这里插入图片描述

1、简单的排序

冒泡排序

遍历每个位置的元素,与相邻的数字作比较,不断交换位置。

def main(nums):
    n=len(nums)
    for i in range(n):
        for j in range(0,n-i-1):
            if nums[j]>nums[j+1]:
                nums[j],nums[j+1]=nums[j+1],nums[j]
    print(nums)

选择排序

每次遍历都找到当前最小值的下标,按照顺序依次放到列表对应位置

def main(nums):
    n=len(nums)
    for i in range(n):
        cur_min = i
        for j in range(i+1,n):
            if nums[j]<nums[cur_min]:
                cur_min=j
        nums[i],nums[cur_min]=nums[cur_min],nums[i]
    print(nums)

插入排序

def main(nums):
    n=len(nums)
    for i in range(1,n):
        j=i
        while j>0:
            if nums[j]<nums[j-1]:
                nums[j],nums[j-1]=nums[j-1],nums[j]
                j-=1
            else:
                break
    print(nums)

希尔排序

def main(list):
    n=len(list)

    gap=n//2

    while gap>0:
        for i in range(gap,n):
            j=i
            while j>=gap:
                if list[j-gap]>list[j]:
                    list[j],list[j-gap]=list[j-gap],list[j]
                    j-=gap
                else:
                    break
        gap//=2
    return list

2、高级排序

快速排序

def quick_sort(nums,left,right):
    if left>=right:
        return
    mid=nums[left]
    low=left
    high=right
    while low<high:
        while nums[high]>=mid and low<high:
            high-=1
        nums[low]=nums[high]
        while nums[low]<=mid and low < high:
            low+=1
        nums[high]=nums[low]
    nums[low]=mid
    quick_sort(nums,left,low)
    quick_sort(nums,low+1,right)

归并排序

def merge_sort(list):
    n=len(list)
    mid=n//2
    if n<=1:
        return list
    left_list=merge_sort(list[:mid])
    right_list=merge_sort(list[mid:])
    left_cur=0
    right_cur=0
    result=[]
    while left_cur<len(left_list) and right_cur<len(right_list):
        if left_list[left_cur]<right_list[right_cur]:
            result.append(left_list[left_cur])
            left_cur+=1
        else:
            result.append(right_list[right_cur])
            right_cur+=1
    result.extend(left_list[left_cur:])
    result.extend(right_list[right_cur:])
    return result

3、Leetcode 1122:数组的相对排序

题目描述
在这里插入图片描述

解题思路
将arr1中的值和对应出现的位置存储在字典中,建立一个cmp函数如果当前x在rank中返回0,rank[i],如果不在返回(1,x),根据这个key对arr1进行排序

代码实现

class Solution:
    def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
        def cmp(x):
            return (0,rank[x]) if x in rank else(1,x)
        
        rank={k:i for i,k in enumerate(arr2)}
        arr1.sort(key=cmp)
        return arr1

4、Leetcode 242:有效的字母异位词

之前使用的是哈希表来存储s和t,这里使用排序对列表化字符串进行排序然后再变成字符串进行比较。
代码实现

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        def str2list(words):
            li=list(words)
            li.sort()
            return "".join(li)
        return str2list(s)==str2list(t)

5、Leetcode 1244:力扣排行榜

题目描述
在这里插入图片描述

解题思路
这道题其实没什么难度,主要是返回topk的总数,这里的做法参考了题解,即把字典中的value拿出来排序存储于列表,再统计k个的组合。也可以直接对字典进行排序然后遍历k次。感觉应该都差不多。如果用heap直接压堆可能会更快一点。

代码实现

class Leaderboard:

    def __init__(self):
        #建立一个字典
        self.dic=collections.defaultdict(int)


    def addScore(self, playerId: int, score: int) -> None:
        self.dic[playerId]+=score


    def top(self, K: int) -> int:
        #先要根据value进行排序
        dic1=sorted([v for v in self.dic.values()],reverse=True)
        return sum(dic1[:K])
        


    def reset(self, playerId: int) -> None:
        self.dic[playerId]=0

6、Leetcode 56:合并区间

题目描述
在这里插入图片描述

解题思路

首先将区间根据区间起始位置进行排序,然后遍历每个区间,维护一个列表,如果当前列表没有或者当前区间的起始位置大于列表中最后一个区间的终止位置,那么就无需合并,直接添加。如果当前区间的起始位置小于了上个区间的终止位置,需要合并。将列表最后一个区间的终止位置改成当前区间的终止位置。

代码实现

class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        #先根据起始位置进行排序
        intervals.sort(key=lambda x:x[0])
        res=[]
        #遍历每个区间
        for interval in intervals:
            #如果当前已经加入res的区间的结束位置小于当前interval的起始位置,直接添加即可
            if not res or res[-1][-1]<interval[0]:
                res.append(interval)
            #如果当前interval的起始值小于merge中存储interval的终止位置,那要将它们合并
            else:
                res[-1][-1]=max(res[-1][-1],interval[1])
        return res

7、剑指Offer 51 数组中的逆序对

题目描述

在这里插入图片描述

代码实现

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        tmp=[0]*len(nums)
        #归并排序
        def merge_sort(l,r):
            #终止条件:
            if l>=r:
                return 0
            #递归的mid
            mid=(l+r)//2
            #左右分别递归
            res=merge_sort(l,mid)+merge_sort(mid+1,r)
            #合并阶段
            #定义两个指针
            i,j=l,mid+1
            #找到当前列表的值域
            tmp[l:r+1]=nums[l:r+1]
            #遍历tmp
            for k in range(l,r+1):
                #如果左指针已经走完,那就不算添加右边的值
                if i==mid+1:
                    nums[k]=tmp[j]
                    j+=1
                #如果右指针已经走完或者当前左指针的值小于右指针
                elif j==r+1 or tmp[i]<=tmp[j]:
                    nums[k]=tmp[i]
                    i+=1
                #如果当前左指针大于右指针,那在添加右指针的同时还要统计逆序对的数量
                else:
                    nums[k]=tmp[j]
                    j+=1
                    #逆序对的数量为左边列表个数减去当前位置i
                    res+=mid-i+1
            return res
        return merge_sort(0,len(nums)-1)

8、Leetcode 491: 翻转对

题目描述
在这里插入图片描述

解题思路
这道题讲道理花费了很长时间,想从上一题直接添加一个判断是否两倍的条件来输出,发现不是很对,因为对于2,3;1这两个子序列,如果在比较2和1不满足两倍以上这个条件后,1就会被加入列表,j的下标也会移动就无法判断3,1了。想了半天发现还是在比较外再添加两个元素,再遍历一遍去添加。

代码实现

class Solution:
    def reversePairs(self, nums: List[int]) -> int:
        tmp=[0]*len(nums)
        #归并排序
        def merge_sort(l,r):
            #终止条件
            if l>=r:
                return 0
            #求出mid的位置
            mid=(l+r)//2
            res=merge_sort(l,mid)+merge_sort(mid+1,r)
            #合并阶段,定义两个指针,指向两个子列表的开头
            i,j=l,mid+1
            #找到当前左右子列表的值域
            tmp[l:r+1]=nums[l:r+1]
            #开始遍历
            for k in range(l,r+1):
                #如果左指针走完,就把每个位置对应右指针
                if i==mid+1:
                    nums[k]=tmp[j]
                    j+=1
                #如果右指针走完或者当前左指针的值小于右指针的值
                elif j==r+1 or tmp[i]<=tmp[j]:
                    nums[k]=tmp[i]
                    i+=1
                #如果当前左指针的值大于右指针的值
                else:
                    nums[k]=tmp[j]
                    j+=1
            ti, tj = l, mid + 1
            while ti <= mid and tj <= r:
                if tmp[ti] <=  2 * tmp[tj]:
                    ti += 1
                else:
                    res+= mid - ti + 1
                    tj += 1
            return res
        return merge_sort(0,len(nums)-1)

第三章 字符串

1、Leetcode 709 转换成小写字母

这道题超级简单,就不做描述了

class Solution:
    def toLowerCase(self, str: str) -> str:
        #建立一个空字符串
        word=""
        #遍历str
        for char in str:
            word+=char.lower()
        return word

2、Leetcode 58:最后一个单词的长度

第一遍提交报错是因为没有考虑多个空格的情况。所以通过判断切割后的字列表的长度判断是否全为空格。

class Solution:
    def lengthOfLastWord(self, s: str) -> int:
        #将字符串分隔开
        word_list=s.split()
        #如果为空
        if len(word_list)==0:
            return 0
        return len(word_list[-1])

3、Leetcode 771:宝石与石头

题目描述
在这里插入图片描述

代码实现

class Solution:
    def numJewelsInStones(self, jewels: str, stones: str) -> int:
        #将宝石类型列表化
        list_j=list(jewels)
        #统计变量
        count=0
        #遍历stones
        for stone in stones:
            if stone in list_j:
                count+=1
        return count

4、剑指offer 50:第一个只出现一次的字符

解题思路
在这里插入图片描述

代码实现

class Solution:
    def firstUniqChar(self, s: str) -> str:
        if len(s)==0:
            return " "
        #先统计s的每个词出现的次数
        dic=collections.defaultdict(list)
        i=0
        for char in s:
            #把每个字母出现在s的位置作为value
            dic[char].append(i)
            i+=1
        #遍历哈希表
        for k,v in dic.items():
            #第一次出现字母对应的位置只有一个的时候,返回其值
            if len(v)==1:
                return k
        #如果遍历完都没出现
        return " "

5、Leetcode 8:字符串转换整数

题目描述
在这里插入图片描述

解题思路
使用re.findall(str)匹配正则,正则表达式:字符串形式,以正负号开头的数字(d)
上下界都要有规定。

代码实现

import re
class Solution:
    def myAtoi(self, str: str) -> int:
        INT_MAX = 2**31-1   
        INT_MIN = -2**31
        str = str.lstrip()      #清除左边多余的空格
        num_re = re.compile(r'^[\+\-]?\d+')   #设置正则规则
        num = num_re.findall(str)   #查找匹配的内容
        num = int(*num) #由于返回的是个列表,解包并且转换成整数
        return max(min(num,INT_MAX),INT_MIN)    #返回值

不使用正则的方法:

class Solution:
    def myAtoi(self, s: str) -> int:
        #判断是否为空
        #去除空格
        slices=list(s.strip())
        if len(slices)==0:return 0
        #对于正负号的处理
        signal= -1 if slices[0]=="-" else 1
        #删除正负号
        if slices[0] in ["+","-"]: del slices[0]
        res,i=0,0
        #遍历字符串且只考虑是数字的字符
        while i <len(slices) and slices[i].isdigit():
            res=res*10+ord(slices[i])-ord("0")
            i+=1
        #返回
        return  max(-2**31,min(signal*res,2**31-1))

6、Leetcode 14:最长公共前缀

题目描述
在这里插入图片描述

分治代码

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        #分治的方法
        def dfs(start,end):
            #终止条件
            if start==end:return strs[start]
            #开始递归
            mid=(start+end)//2
            left=dfs(start,mid)
            right=dfs(mid+1,end)
            #对比两个词的长度取最小
            min_len=min(len(left),len(right))
            #遍历这个最小长度
            for i in range(min_len):
                if left[i]!=right[i]:
                    return left[:i]
            #如果一直相同,就返回最短的词
            return left[:min_len]
        return "" if len(strs)==0 else dfs(0,len(strs)-1)

纵向比较代码

class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        #特殊情况
        if not strs:
            return ""
        #拿出一个字作为标准,因为是公共前缀,所以哪个都可以
        length=len(strs[0])
        #统计有多少个词
        count=len(strs)
        #遍历标准词的每一个位置
        for i in range(length):
            #如果i到达了其他词的最大长度或者当前标准词的位置和其他词的相同位置不同,结束
            if any(i==len(strs[j]) or strs[j][i]!=strs[0][i] for j in range(1,count)):
                return strs[0][:i]
        #如果完全相同
        return strs[0]

7、Leetcode 344:反转字符串

题目描述
在这里插入图片描述

代码实现
这种题是真实存在的么,。。。。。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        return s.reverse()

8、Leetcode 541:反转字符串ii

题目描述
在这里插入图片描述

解题思路
其实这道题作为简单题唯一的一点小的难点在于不足2k个的时候怎么处理,在下面的代码中可以看到,我们是隔2k个一取得,当最后不足k个的时候依然进行了反转,当在k和2k之间时,大于k得就没有反转,满足题意。

代码实现

class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        n=len(s)
        li=list(s)
        for i in range(0,n,k*2):
            #将前k个进行交换
            li[i:i+k]=s[i:i+k][::-1]
        return "".join(li)

9、Leetcode 151:反转字符串里的单词

题目描述
在这里插入图片描述

解题思路

  • 切片
  • 反转
  • 列表变字符串

代码实现

class Solution:
    def reverseWords(self, s: str) -> str:
        #先将单词取出储存于列表
        word_list=s.split()
        #将列表反转
        word_list.reverse()
        #输出
        return " ".join(word_list)

10、Leetcode 557:反转字符串中的单词III

题目描述
在这里插入图片描述

解题思路
没看题解,不知道还有没有更好的方法。步骤:

  • 每个单词空格切分,对每个单词列表化:list of list
  • 对于每个list后的词,翻转,转换为字符串添加到res
  • res转换为字符串,空格分开。

代码实现

class Solution:
    def reverseWords(self, s: str) -> str:
        res=[]
        #切片
        word_list=[list(word) for word in s.split()]
        for word in word_list:
            word.reverse()
            res.append("".join(word))
        return " ".join(res)

11、Leetcode 917:仅仅反转字母

题目描述
在这里插入图片描述

解题思路
感觉自己的代码写的真的很繁琐。。。。

  • 1、把S中纯字母的部分拿出来,列表化为char_list,翻转
  • 2、遍历列表化的S,对于为字母的位置,添加char_list得元素,对于为符号的,移动i指针
  • 3、join返回

代码实现

class Solution:
    def reverseOnlyLetters(self, S: str) -> str:
        #先把S中的纯字母倒叙拿出
        char_list=[char for char in S if char.isalpha()]
        #翻转一下
        char_list.reverse()
        #遍历S,把char为纯字母的地方插入char_list
        i,j=0,0
        pre_list=list(S)
        while i < len(S):
            if S[i].isalpha():
                pre_list[i]=char_list[j]
                i+=1
                j+=1
            else:
                i+=1
        return "".join(pre_list)

参考了题解,直接用栈取存储需要反转的字母,这样不需要要反转只要每次pop就可以,真的妙极了!!!!!!!!!

class Solution(object):
    def reverseOnlyLetters(self, S):
        letters = [c for c in S if c.isalpha()]
        ans = []
        for c in S:
            if c.isalpha():
                ans.append(letters.pop())
            else:
                ans.append(c)
        return "".join(ans)

12、Leetcode 242:有效的字母异位词重写

解题思路

  • 排序
  • 哈希表
    代码实现
class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        #排序
        li1=list(s)
        li2=list(t)
        li1.sort()
        li2.sort()
        return li1==li2

13、Leetcode 49:字母异位词分组:

写过好多次了,不解释了,哈希表用起来,返回list of list

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        #建立字典
        dic=collections.defaultdict(list)
        #遍历单词
        for word in strs:
            key="".join(sorted(word))
            dic[key].append(word)
        return [ v for k,v in dic.items()]

14、Leetcode 438:找到字符串中的所有字母异位词

题目描述
在这里插入图片描述

解题思路
规定两个个p和s得长度为26得列表存储它们对应的词,第一次先查看s得前m个字符(m为p的长度),判断一下他们是否相同,然后在遍历s的过程中不算的对s_cnt进行加减,新位置的字母对应的位置相加,原来位置的字母在s_cnt得位置减掉,当s_cnt和p_cnt相等时,代表当前为字母异位词,添加当前位置的第一个索引i-(m-1)到res中。

代码实现

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        n, m, res = len(s), len(p), []
        if n < m: return res
        p_cnt = [0] * 26
        s_cnt = [0] * 26
        for i in range(m):
            p_cnt[ord(p[i]) - ord('a')] += 1
            s_cnt[ord(s[i]) - ord('a')] += 1
        if s_cnt == p_cnt:
            res.append(0)
        
        for i in range(m, n):
            s_cnt[ord(s[i - m]) - ord('a')] -= 1
            s_cnt[ord(s[i]) - ord('a')] += 1
            if s_cnt == p_cnt:
                res.append(i - m + 1)
        return res

15、Leetcode 1143:最长公共子序列重写

代码实现

class Solution:
    def longestCommonSubsequence(self, text1: str, text2: str) -> int:
        #特殊条件:text1或者text2有一个不存在
        if not text1 or not text2:
            return 0
        m,n=len(text1),len(text2)
        #建立dp
        dp=[[0]*(n+1) for _ in range(m+1)]
        #开始遍历
        for i in range(1,m+1):
            for j in range(1,n+1):
                #如果当前字符相同
                if text1[i-1]==text2[j-1]:
                    dp[i][j]=1+dp[i-1][j-1]
                #如果不同,对比i,j-1和i-1,j得更大的
                else:
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1])
        return dp[-1][-1]

16、Leetcode 125:验证回文串

题目描述
在这里插入图片描述

解题思路
也可以直接把第二步变成压栈的形式然后pop
代码实现

class Solution:
    def isPalindrome(self, s: str) -> bool:
        n=len(s)
        #先把数字和字母添加到列表中
        word_list=[c.lower() for c in s if c.isdigit() or c.isalpha()]
        #定义双指针起始位置
        i,j=0,len(word_list)-1
        while i < j:
            if word_list[i]==word_list[j]:
                i+=1
                j-=1
            else:
                return False
        return True

17、Leetcode 680:验证回文字符串ii

题目描述
在这里插入图片描述

解题思路
一开始的做法是因为只删除一次,所以先返回所有的结果,再判断这些结果是否有一个是回文串,但时间复杂度太高了。下面的做法是,因为只允许删除一次,所以当左右指针移动的过程中遇到不相等的时候,删除low或者high的其中一个,然后用一层递归,去判断删除后的是不是。

代码实现

class Solution:
    def validPalindrome(self, s: str) -> bool:
        def valids(left,right):
            while left<right:
                if s[left]==s[right]:
                    left+=1
                    right-=1
                else:
                    return False
            return True
        #定位左右指针
        low,high=0,len(s)-1
        #循环
        while low<high:
            if s[low]==s[high]:
                #直接移动左右指针
                low+=1
                high-=1
            else:
                #删除当前low或者high
                return valids(low+1,high) or valids(low,high-1)
        #如果遍历完都是相同得
        return True

18、Leetcode 5:最长回文子串

题目描述
在这里插入图片描述

解题思路
中心扩展法或者动态规划均可

代码实现

class Solution:
    def expandAroundCenter(self, s, left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return left + 1, right - 1

    def longestPalindrome(self, s: str) -> str:
        start, end = 0, 0
        for i in range(len(s)):
            left1, right1 = self.expandAroundCenter(s, i, i)
            left2, right2 = self.expandAroundCenter(s, i, i + 1)
            if right1 - left1 > end - start:
                start, end = left1, right1
            if right2 - left2 > end - start:
                start, end = left2, right2
        return s[start: end + 1]
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        dp = [[False] * n for _ in range(n)]
        ans = ""
        # 枚举子串的长度 l+1
        for l in range(n):
            # 枚举子串的起始位置 i,这样可以通过 j=i+l 得到子串的结束位置
            for i in range(n):
                j = i + l
                if j >= len(s):
                    break
                if l == 0:
                    dp[i][j] = True
                elif l == 1:
                    dp[i][j] = (s[i] == s[j])
                else:
                    dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
                if dp[i][j] and l + 1 > len(ans):
                    ans = s[i:j+1]
        return ans

19、Leetcode 72:编辑距离重写

写过好多遍了,滚瓜烂熟,直接上代码

class Solution:
    def minDistance(self, word1: str, word2: str) -> int:
        m,n=len(word1),len(word2)
        #建立dp
        dp=[[0]*(n+1) for _ in range(m+1)]
        #当word1为空时
        for i in range(n+1):
            dp[0][i]=i
        #当word2为空时,
        for j in range(m+1):
            dp[j][0]=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-1],
                                dp[i-1][j],
                                dp[i][j-1])+1
        return dp[-1][-1]

20、Leetcode 10:正则表达式匹配

题目描述
在这里插入图片描述

解题思路
对于当前不是 “ * ” 的就只匹配当前对应位置的i和j,如果是 “ * ”,就匹配i和j-2,因为j-1可以选择不匹配。如果是.就直接返回true即可,不需要对比。

代码实现

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m, n = len(s), len(p)

        def matches(i: int, j: int) -> bool:
            if i == 0:
                return False
            if p[j - 1] == '.':
                return True
            return s[i - 1] == p[j - 1]

        f = [[False] * (n + 1) for _ in range(m + 1)]
        f[0][0] = True
        for i in range(m + 1):
            for j in range(1, n + 1):
                if p[j - 1] == '*':
                    f[i][j] |= f[i][j - 2]
                    if matches(i, j - 1):
                        f[i][j] |= f[i - 1][j]
                else:
                    if matches(i, j):
                        f[i][j] |= f[i - 1][j - 1]
        return f[m][n]

21、Leetcode 44:通配符匹配

题目描述
在这里插入图片描述

代码实现

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m,n=len(s),len(p)
        #建立dp,当p为空时一定是false
        dp=[[False]*(n+1) for _ in range(m+1)]
        dp[0][0]=True
        #当s为空,p不为空时,要看p对应的*
        for i in range(1,n+1):
            if p[i-1]=="*":
                dp[0][i]=True
            else:
                break
        #开始循环
        for i in range(1,m+1):
            for j in range(1,n+1):
                #当j为*号时
                if p[j-1]=="*":
                    dp[i][j]=dp[i][j-1]|dp[i-1][j]
                elif p[j-1]=="?" or s[i-1]==p[j-1]:
                    dp[i][j]=dp[i-1][j-1]
        return dp[-1][-1]

22、Leetcode 115:不同的子序列重写

再写的时候觉得比较需要思考的是即使当si和tj想同时,可以匹配也可以不匹配,因为没准i后面的还可以匹配到j,所以是两种情况加和的关系。
代码实现

class Solution:
    def numDistinct(self, s: str, t: str) -> int:
        #统计两个字符串的长度
        m,n=len(s),len(t)
        #以t为子串,如果t比s长,不符合题意
        if m<n:
            return 0
        #建立储存的状态矩阵
        dp=[[0]*(n+1) for _ in range(m+1)]
        #初始化,如果n=0,那么它可以使s的任何子串
        for i in range(m+1):
            dp[i][n]=1
        #如果m=0,没有字串
        #开始遍历
        for i in range(m-1,-1,-1):
            for j in range(n-1,-1,-1):
                #如果当前字母匹配
                if s[i]==t[j]:
                    #那么有可能是从s+1,j+1转移,也可能是s+1,j转移
                    dp[i][j]=dp[i+1][j+1]+dp[i+1][j]
                else:
                    #如果不相等,只能考虑s+1,j
                    dp[i][j]=dp[i+1][j]
        return dp[0][0]

你可能感兴趣的:(列表,leetcode,数据结构)