5325包含所有三种字符的子字符串数目
题目:给你一个字符串 s
,它只包含三种字符 a, b 和 c 。请你返回 a,b 和 c 都 至少 出现过一次的子字符串数目。
链接:https://leetcode-cn.com/problems/number-of-substrings-containing-all-three-characters/
法一:自己的代码
思路:刚开始的思路是利用类似戳气球的方法,dp[i][j]表示字符串中从i到j的符合条件的字符串的个数,进而推导从dp[i+1][j]和dp[i][j-1]如何计算出dp[i][j],但是前面两个有重复的部分,推理很复杂,难以用dp进行记录,考虑改变dp的定义,dp[i][j]表示字符串中从0到i,a b c最后一次出现的索引,而以字符s[i]结尾的满足条件的子字符串的个数,即最小索引的值加一,
class Solution: def numberOfSubstrings(self, s: str) -> int: size = len(s) dp = [[-1] * (size+1) for i in range(3)] d = {'a':0, 'b':1, 'c':2} res = 0 for col in range(1, size+1): for row in range(3): dp[row][col] = dp[row][col-1] dp[d[s[col-1]]][col] = col - 1 r = min(dp[0][col], dp[1][col], dp[2][col]) if r != -1: res += (r+1) return res
改进后的dp数组,只需更新三个值即可
class Solution: def numberOfSubstrings(self, s: str) -> int: d = {'a':0, 'b':0, 'c':0} res = 0 for i,j in enumerate(s): d[j] = i + 1 print(d) # a b c 的最小值即字符串中以s[i]结尾的满足条件的子字符串的个数 res += min(d.values()) return res if __name__ == '__main__': solution = Solution() # result = solution.numberOfSubstrings(s = "abcabcccccc") result = solution.numberOfSubstrings(s = "aaabbbccc") # result = solution.numberOfSubstrings(s = "aaabc") print(result)
法二:双指针法
思路:我们使用首尾指针维护一个滑动窗口。
如果窗口内没有 aaa,bbb,ccc,尾指针右移来寻找字符直到窗口内包含 aaa,bbb,ccc;
如果窗口内包含 aaa,bbb,ccc,当窗口继续向右拉开时肯定仍然包含 aaa,bbb,ccc,所以直接加上窗口右侧到末尾的距离;
然后左侧指针右移,每移动一步进行以上两种情况的判读即可。
之所以用这个解法是因为,确定一个字符串只需要知道两个因素,即左边的索引和右边的索引,这里的双指针法实际上是分类讨论,先让左指针不动,移动右指针,一旦找到满足条件的,再移动左指针,