滑动窗口: 快慢指针在数组上的应用

链表子串数组题, 用双指针别犹豫. 双指针家三兄弟, 各个都是万人迷.
快慢指针最神奇, 链表操作无压力. 归并排序找中点, 链表成环搞判定.
左右指针最常见, 左右两端相向行. 反转数组要靠它, 二分搜索是弟弟.
滑动窗口最困难, 子串问题全靠它. 左右指针滑窗口, 一前一后齐头进.

大致逻辑

T(2n)O(n)

left, right = 0, 0
while right < len(s):
    # 增大窗口
	window.add(s[right])
    right += 1
    
    while window needs shrink:
        # 缩小窗口
        window.remove(s[left])
        left += 1

框架

  • 寻找一个可行解
  • 优化这个可行解
  • 找到最优解
def slidingWindow(s: str, t: str):
    need, window = defaultdict(int), defaultdict(int)
    for c in t:
        need[c] += 1
    left, right, valid = 0, 0, 0
    while right < len(s):
        c = s[right] # c 是即将移入窗口的字符
        right += 1 # 右移窗口
        # ... 进行窗口内数据的一系列更新
        
        print("window: [%d, %d)\n" % left, right)
        
        # 判断左侧窗口是否要收缩
        while window needs shrink:
            d = s[left] # d 是即将移出窗口的字符
            left += 1 # 左移窗口
            # ... 进行窗口内数据的一系列更新

default dict

defaultdict(factory: function)

def def_value():
    return "Not Present"
# Defining the dict
d = defaultdict(def_value)

76 最小覆盖子串

def minWindow(self, s: str, t: str) -> str:

    need = defaultdict(int)
    window = defaultdict(int)
    for c in t:
        need[c] += 1

    left, right, valid = 0, 0, 0
    start, lenght = 0, sys.maxsize

    while right < len(s):
        c = s[right]  # c 是即将移入窗口的字符
        right += 1  # 右移窗口
        # ... 进行窗口内数据的一系列更新
        if c in need:
            window[c] += 1
            if window[c] == need[c]:
                valid += 1

        # 判断左侧窗口是否要收缩
        while valid == len(need):
            if right - left < lenght:
                start = left
                lenght = right - left
            d = s[left]  # d 是即将移出窗口的字符
            left += 1  # 左移窗口
            # ... 进行窗口内数据的一系列更新
            if d in need:
                if window[d] == need[d]:
                    valid -= 1
                window[d] -= 1
    return "" if lenght == sys.maxsize else s[start:start+lenght]

567 s2的子串是否包含s1的排列

class Solution:
    def checkInclusion(self, s1: str, s2: str) -> bool:

        NEED, window = defaultdict(int), defaultdict(int)
        for item in s1:
            NEED[item] += 1
        left, right = 0, 0
        valid = 0
        while right < len(s2):
            c = s2[right]
            right += 1
            if c in NEED:
                window[c] += 1
                if window[c] == NEED[c]:
                    valid += 1

            while right - left >= len(s1):  # >
                if valid == len(NEED):  # len(s1)
                    return True

                d = s2[left]
                left += 1
                if d in NEED:
                    if window[d] == NEED[d]:
                        valid -= 1
                    window[d] -= 1
        return False

438 异位子串起始索引

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:

        NEED, window = defaultdict(int), defaultdict(int)
        for item in p:
            NEED[item] += 1
        left, right = 0, 0
        valid = 0
        res = list()
        while right < len(s):
            c = s[right]
            right += 1
            if c in NEED:
                window[c] += 1
                if window[c] == NEED[c]:
                    valid += 1

            while right - left >= len(p):
                if valid == len(NEED):
                    res.append(left)

                d = s[left]
                left += 1
                if d in NEED:
                    if window[d] == NEED[d]:
                        valid -= 1
                    window[d] -= 1
        return res

3 最长无重复子串

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:

        window = defaultdict(int)
        left, right = 0, 0
        res = 0
        while right < len(s):
            c = s[right]
            right += 1
            window[c] += 1

            while window[c] > 1:
                d = s[left]
                left += 1
                window[d] -= 1
            res = max(res, right - left)
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值