Skip to content

Latest commit

 

History

History
347 lines (259 loc) · 10.3 KB

技巧-双指针-滑动窗口.md

File metadata and controls

347 lines (259 loc) · 10.3 KB

双指针

Problems


LeetCode 0003 无重复字符的最长子串 (中等, 2022-02)

滑动窗口 LeetCode

问题简述
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

3. 无重复字符的最长子串 - 力扣(LeetCode)

思路:滑动窗口
  • 维护一个已经出现过的字符集合,详见代码;
Python
class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        
        used = set()
        l = r = 0  # 窗口边界
        ret = 0
        while r < len(s):
            while s[r] in used:  # 如果已经出现过则移出
                # 注意这里要 while 判断,因为 l 指针不一定刚好指向这个重复的字符,要一直移动直到把 r 指向的字符移出
                used.remove(s[l])
                l += 1
            ret = max(ret, r - l + 1)
            used.add(s[r])
            r += 1
        return ret

优化:直接移动 l 指针到重复字符的下一个位置,减少 l 指针移动;

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        used = dict()
        l = r = 0  # [l, r] 闭区间
        ret = 0
        while r < len(s):
            if s[r] in used and l <= used[s[r]]:  # l <= used[s[r]] 的意思是重复字符出现在窗口内;
                l = used[s[r]] + 1
            ret = max(ret, r - l + 1)
            used[s[r]] = r
            r += 1
        return ret

剑指Offer 5901 滑动窗口的最大值 (困难, 2022-01)

滑动窗口 单调队列 剑指Offer

问题简述
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
详细描述
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。

示例:
    输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
    输出: [3,3,5,5,6,7] 
    解释: 
      滑动窗口的位置                最大值
    ---------------               -----
    [1  3  -1] -3  5  3  6  7       3
     1 [3  -1  -3] 5  3  6  7       3
     1  3 [-1  -3  5] 3  6  7       5
     1  3  -1 [-3  5  3] 6  7       5
     1  3  -1  -3 [5  3  6] 7       6
     1  3  -1  -3  5 [3  6  7]      7

提示:
    你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
Python
  • 官方写法的区别:
    • 官方的单调队列维护的是数组下标,通过判断下标位置来确定是否移除队首元素;因此可以使用严格单调队列;而下面的写法中使用值来判断是否移除队首,因此使用的是非严格单调队列(相关代码段:if q[0] == nums[i - k]: q.popleft()
class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        from collections import deque

        if not nums: return []

        # 初始化单调队列,对任意 i > j,有 q[i] >= q[j]
        q = deque()
        for x in nums[:k]:
            while q and q[-1] < x:  # 注意这里是非严格单调的
                q.pop()
            q.append(x)
        # print(q)

        ret = [q[0]]  # 
        for i in range(k, len(nums)):
            if q[0] == nums[i - k]:  # 因为是通过值判断,所以需要保留所有相同的最大值,所以队列是非严格单调的
                q.popleft()
            while q and q[-1] < nums[i]:
                q.pop()
            q.append(nums[i])
            ret.append(q[0])
            # print(q)
        
        return ret

牛客 0028 最小覆盖子串 (较难, 2022-02)

滑动窗口 牛客

问题简述
给出两个字符串 s 和 t,要求在 s 中找出最短的包含 t 中所有字符的连续子串。

最小覆盖子串_牛客题霸_牛客网

思路:滑动窗口
  • 应用模板比较复杂的一题;
滑动窗口模板
l = r = 0  # 初始化 [l, r] 闭区间
while r < N:
    # 更新窗口
    while check():  # 满足要求进入循环,不满足退出
        # 更新答案
        l += 1  # 移动左边界
    r += 1  # 移动右边界
Python
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param S string字符串 
# @param T string字符串 
# @return string字符串
#
class Solution:
    def minWindow(self , S: str, T: str) -> str:
        # write code here
        
        from collections import Counter, defaultdict
        
        l, r = 0, 0
        N = len(S)
        ret = S  # 初始化为最大的可能,但是注意,可能有无结果的情况,所以还需要一个变量记录答案是否存在
        flag = -1  # 记录是否出现过匹配串,避免无答案的情况
        need = Counter(T)
        used = defaultdict(int)
        
        def check():  # 检验是否满足情况
            for k, v in need.items():
                if k not in used or used[k] < need[k]:
                    return False
            return True
        
        while r < N:
            used[S[r]] += 1
            while check():
                flag = 1
                if r - l < len(ret):
                    ret = S[l: r + 1]
                used[S[l]] -= 1
                l += 1
            r += 1
        
        return ret if flag != -1 else ''

牛客 0041 最长无重复子数组 (中等, 2022-03)

滑动窗口 牛客

问题简述
给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组

最长无重复子数组_牛客题霸_牛客网

思路:滑动窗口
  • 标准的滑动窗口模板问题;
Python
class Solution:
    def maxLength(self , arr: List[int]) -> int:
        if not arr: return 0
        
        N = len(arr)
        l, r = 0, 0  # [l, r] 滑动窗口闭区间
        
        ret = 1
        book = set()
        while r < N:
            # 当不满足条件时,循环移动左边界直到再次满足
            while arr[r] in book:  # 注意这里判断的是 arr[r]
                book.remove(arr[l])  # 这里移除的是 arr[l]
                l += 1
            
            ret = max(ret, r - l + 1)  # 更新结果
            book.add(arr[r])
            r += 1
        
        return ret