字符串与连续问题的处理
滑动窗口
连续字符串,双指针。
查看串中是否有串 leetcode 28
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
class Solution:
def strStr(self,haystack,needle):
start = 0
for end in range(len(needle)-1,len(haystack)):
#这里+1是因为前面已经把末尾包含进来了
if needle == haystack[start:end+1]:
return start
start+=1
return -1
字符串的排列 leetcode 567
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
from collections import Counter
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
target = Counter(s1)
start = 0
for end in range(len(s1)-1,len(s2)):
if target == Counter(s2[start:end+1]):
return True
else:
start+=1
return False
- 乍一看很难,很容易思维定式的想到全排列,问题是全排列这个复杂度相当高,得算到啥时候,可是其实并不是非要全排列的全部形式,只要知道每个对应的元素有几个就可以了。
- 只要引入collections Counter这个包,问题就很愉快的转化成28了。
最长不重复子串 leetcode 3
class Solution:
def lengthOfLongestSubString(self,str):
start = 0
mark = set()
max_length = float('-inf')
for end in range(len(str)):
while start<=end and str[end] in mark:
mark.remove(str[start])
start+=1
mark.add(str[end])
max_length = max(max_length,end-start+1)
if max_length ==float('-inf'):
return 0
else:
return max_length
- 不定长。
- 判断长度问题无需再初始化一个字符串,直接在原串上比较长度即可。
- 先看看尾部在不在之内,如果在,满足字符串的约束,先删除头部,不在了之后才开始添加。
- 都是先往里放,只不过是这个题目放不了,因为只能放不重复的,所以先判断,所以这里再次明确while有if的能力,是循环带上判断,不仅仅是for。
长度最短子数组 leetcode 209
找出连续和大于s的最短子数组
class Soultion:
def minSubArrayLen(self,s,nums):
start = 0
min_len = float('inf')
cur_sum = 0
for end in range(len(nums)):
cur_sum+=nums[end]
while cur_sum>=s:
min_len = min(min_len,end-start+1)
cur_sum-=nums[start]
start+=1
if min_len == float('inf'):
return 0
return min_len
水果成篮 leetcode 904
连续子数组中种类不大于2的最长序列长度是多少
class Solution:
def totalFruit(self,tree):
start = 0
max_len = float('-inf')
adict = dict()
for end in range(len(tree)):
if tree[end] not in adict:
adict[tree[end]] = 1
else:
adict[tree[end]]+=1
while len(adict)>2:
adict[tree[start]]-=1
if adict[tree[start]] == 0:
del adict[tree[start]]
start+=1
#这个判断写在哪里合适,有可能一直种类都没大于2,所以在while的外面
max_len = max(max_len,end-start+1)
if max_len == float('-inf'):
return 0
else:
return max_len
- 两个数据结构,一个是记录当前数字种类的dict。
- 另一个是记录原字符串的起止位置。
lc 1248. 统计「优美子数组」
class Solution:
def numberOfSubarrays(self, nums: List[int], k: int) -> int:
def ltk(nums,k):
start = 0
odd_count = 0
res = 0
for end in range(len(nums)):
if nums[end]%2==1:
odd_count+=1
while odd_count>k:
# 满足条件的减去
if nums[start]%2==1:
odd_count-=1
# 满足与否都要往前走
start+=1
# 即是跨度,又是个数,正好是组合数
res += end-start+1
return res
return ltk(nums,k)-ltk(nums,k-1)
- 连续恰好为
前缀和
列表中连续和为k的个数 leetcode 560
nums = [1,0,2,1] , k = 3
{0:1,1:2,3:1,4:1}
class Soultion:
def subarraySum(self,nums,k):
#因为前缀和是到该位置和的个数,所以初始化为0有1个肯定没错,后面还有0再追加即可
adict = {0:1}
cur_sum = 0
count = 0
for num in nums:
cur_sum+=num
if cur_sum-k in adict:
count+=adict[cur_sum-k]
if cur_sum in adict:
adict[cur_sum]+=1
else:
adict[cur_sum]=1
return count
- 放在这个模块里因为也是有字符串连续的意思。
- 这个题目相当于求pdf,然后每次找到差如果在list中则加上对应的数字为最后有的个数,twosum类似
最长和谐子序列 lc 594
class Solution:
def findLHS(self, nums: List[int]) -> int:
c = Counter(nums)
res = 0
for x in c:
if x+1 in c:
res = max(res,c[x]+c[x+1])
return res
- 仅仅是和上面的题长得有点像,但是没有连续的要求,所以就很简单,依次的往下找就可以。
- 这个题目读起来非常迷惑,转成这样写不容易想到。
通过删除字母匹配到字典里最长单词 lc 524
输入:s = “abpcplea”, d = [“ale”,“apple”,“monkey”,“plea”]
输出: “apple”
# 比较好想,上面的解法需要记住之前的题目
class Solution:
def findLongestWord(self, s: str, dictionary: List[str]) -> str:
dictionary.sort(key = lambda x:(-len(x),x))
for d in dictionary:
start = 0
for end in range(len(s)):
if start<len(d) and d[start] == s[end]:
start+=1
if start==len(d):
return d
return ''
# 下面的代码废弃掉
class Solution:
def findLongestWord(self, s: str, d: List[str]) -> str:
# d.sort(key = lambda i:len(i),reverse=True)
#先按照长度长度一样再按照字典序
d.sort(key=lambda x:(-len(x), x))
def isSubseq(word, s):
i = 0
for c in s:
if c == word[i]:
i += 1
if i == len(word):
return True
return False
for word in d:
if isSubseq(word, s):
return word
return ""
- sort的二级排序,框架就是for的这段框架。
- 涉及到字符串的是上面那个方法,让source字符串往后移动,当一样的时候让target+1,目标是target的长度到头就找到了。不太容易写的是让谁移动,让source一直移动,找到了target,t移动一下,直到t到了头。
同构字符串 lc 205
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
if len(s)!=len(t):
return False
return self.halfIsom(s,t) and self.halfIsom(t,s)
def halfIsom(self,s,t):
lookup = {}
for i in range(len(s)):
if s[i] not in lookup:
lookup[s[i]] = t[i]
elif lookup[s[i]]!=t[i]:
return False
return True
- 比较自然的想到是dict,但是需要想到是遍历的形式去建设对应map,如果都通过就ok,不通过就false
- 难点二是看实例,正反的map是不一样的,不要强求,不一样就不一样。
计数二进制子串 lc 696
给定一个字符串 s,计算具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是连续的。
输入: “00110011”
输出: 6
解释: 有6个子串具有相同数量的连续1和0:“0011”,“01”,“1100”,“10”,“0011” 和 “01”。
class Solution:
def countBinarySubstrings(self, s: str) -> int:
res = 0
for i in range(len(s)-1):
if int(s[i])+int(s[i+1])==1:
index = 0
while i>=index and i+1+index<len(s) and s[i]==s[i-index] and s[i+1]==s[i+1+index]:
index+=1
res+=1
return res
# 以下的想法很奇特废弃掉
class Solution:
def countBinarySubstrings(self, s: str) -> int:
if len(s)<2:
return 0
nums = []
tmp = s[0]
#最先开始这是0
count = 0
for i in s:
if i==tmp:
count+=1
else:
nums.append(count)
tmp=i
#有一次之后这是1,这样就穿起来了
count=1
nums.append(count)
ans = 0
for i in range(len(nums)-1):
ans+=min(nums[i],nums[i+1])
return ans
- 和nlp常用方法类似,交换角色,移动指针。
- ==解法很巧妙依次的往后面取,两两的取小的即是他们的交集。==
- 可以这样也是后无效性,因为必须要仅仅贴在一起。
- 先找到分裂点,**分裂开只需要保证两边的持续一样就可以,所以再加一个指针。**也是常用技巧之一。
- 这样的计数不是+1就是res+=res+1
字符串转数字 lc 8
class Solution(object):
def myAtoi(self, s):
"""
:type s: str
:rtype: int
"""
s = s.lstrip()
if not s:
return 0
sign = -1 if s[0] == "-" else 1
if sign == -1 or s[0] == "+":
s = s[1:]
d = 0
for i in s:
if i.isdigit():
d *= 10
d += ord(i) - 48
else:
break
# 在小里求大,大里求小
return max(-2**31, min(sign * d,2**31-1))
#舍弃下面的解法,实在是太乱了,这个题目本身就非常的乱
class Solution:
def myAtoi(self, s: str) -> int:
stripS = s.strip()
#如果只有一个'+'没数字后面又group不到
if stripS == '' or stripS=='-' or stripS=='+':
return 0
#补充去除不能满足的模式
s1 = re.match('[^\d]+',stripS.lstrip('-').strip('+'))
if s1!=None:
return 0
else:
#核心,但是也只能找到这样一种模式
s1 = re.search('\-*\+*\d+',stripS).group()
if s1[0:2]=='--' or s1[0:2]=='-+' or s1[0:2]=='++':
return 0
result = int(s1)
if result>0:
return 2**31-1 if result> 2**31-1 else result
else:
return -2**31 if result<-2**31 else result
- 数字前面有0还原正常数字的方法如上d=d*10,d+=s[i]