(LeetCode 3&11&15&18&76)滑动窗口(双指针)

题目描述:

(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第1张图片

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        if not s:
            return 0
        left = 0
        lookup = set() 
        max_len = 0
        cur_len = 0
        for i in range(len(s)):
            cur_len += 1
            while s[i] in lookup:
                lookup.remove(s[left])
                left += 1
                cur_len -= 1
            if cur_len > max_len:
                max_len = cur_len
            lookup.add(s[i])
        return max_len

思路:滑动窗口

一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,只要把队列的左边的元素移出就行了,直到满足题目要求!一直维持这样的队列,找出队列出现最长的长度时候,求出解!

(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第2张图片

class Solution:
    def maxArea(self, height: List[int]) -> int:
        i=0
        j=len(height)-1
        max_A=0
        while imax_A:
                max_A=curlong*curhigh
            if height[i]==min(height[i],height[j]):
                i+=1
            else:
                j-=1
        return max_A

两线段之间形成的区域总是会受到其中较短那条长度的限制。此外,两线段距离越远,得到的面积就越大。

我们在由线段长度构成的数组中使用两个指针,一个放在开始,一个置于末尾。 此外,我们会使用变量 max_A 来持续存储到目前为止所获得的最大面积。 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 max_A,并将指向较短线段的指针向较长线段那端移动一步。因为最初我们考虑由最外围两条线段构成的区域。现在,为了使面积最大化,我们需要考虑更长的两条线段之间的区域。如果我们试图将指向较长线段的指针向内侧移动,矩形区域的面积将受限于较短的线段而不会获得任何增加。但是,在同样的条件下,移动指向较短线段的指针尽管造成了矩形宽度的减小,但却可能会有助于面积的增大。因为移动较短线段的指针会得到一条相对较长的线段,这可以克服由宽度减小而引起的面积减小。

(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第3张图片

class Solution:
    def threeSum(self, nums: [int]) -> [[int]]:
    	#排序
        nums.sort()
        res, k = [], 0
        for k in range(len(nums) - 2):
        	# 因为排序以后j > i > k
            if nums[k] > 0: break 
            # 跳过相同的数
            if k > 0 and nums[k] == nums[k - 1]: continue 
            i, j = k + 1, len(nums) - 1
            while i < j:
                s = nums[k] + nums[i] + nums[j]
                if s < 0:
                    i += 1
                     # 跳过相同的数
                    while i < j and nums[i] == nums[i - 1]: i += 1
                elif s > 0:
                    j -= 1
                     # 跳过相同的数
                    while i < j and nums[j] == nums[j + 1]: j -= 1
                else:
                    res.append([nums[k], nums[i], nums[j]])
                    i += 1
                    j -= 1
                     # 跳过相同的数
                    while i < j and nums[i] == nums[i - 1]: i += 1
                    while i < j and nums[j] == nums[j + 1]: j -= 1
        return res

(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第4张图片

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        n = len(nums)
        if n < 4: return []
        nums.sort()
        res = []
        for i in range(n-3):
            # 防止重复 数组进入 res
            if i > 0 and nums[i] == nums[i-1]:
                continue
            # 当数组最小值和都大于target 跳出
            if nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target:
                break
            # 当数组最大值和都小于target,说明i这个数还是太小,遍历下一个
            if nums[i] + nums[n-1] + nums[n-2] + nums[n-3] < target:
                continue
            for j in range(i+1,n-2):
                # 防止重复 数组进入 res
                if j - i > 1 and nums[j] == nums[j-1]:
                    continue
                # 同理
                if nums[i] + nums[j] + nums[j+1] + nums[j+2] > target:
                    break
                # 同理
                if nums[i] + nums[j] + nums[n-1] + nums[n-2] < target:
                    continue
                # 双指针
                left = j + 1
                right = n - 1
                while left < right:
                    tmp = nums[i] + nums[j] + nums[left] + nums[right]
                    if tmp == target:
                        res.append([nums[i],nums[j],nums[left],nums[right]])
                        while left < right and nums[left] == nums[left+1]:
                            left += 1
                        while left < right and nums[right] == nums[right-1]:
                            right -= 1
                        left += 1
                        right -= 1
                    elif tmp > target:
                        right -= 1
                    else:
                        left += 1
        return res


使用双循环固定两个数,用双指针找另外两个数,通过比较与target 的大小,移动指针。

里面有一些优化,剪枝掉了一些情况!

所以时间复杂度不超过 O ( n 3 ) O(n^{3}) O(n3)

(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第5张图片

class Solution:
    def lengthOfLongestSubstring(self, s):
        from collections import defaultdict
        lookup = defaultdict(int)
        start = 0
        end = 0
        max_len = 0
        counter = 0
        while end < len(s):
            if lookup[s[end]] > 0:
                counter += 1
            lookup[s[end]] += 1
            end += 1
            while counter > 0:
                if lookup[s[start]] > 1:
                    counter -= 1
                lookup[s[start]] -= 1
                start += 1
            max_len = max(max_len, end - start)
        return max_len

思想:

  1. 初始,start指针和end指针都指向s的第一个元素.

  2. 将 end 指针右移,扩张窗口,直到得到一个可行窗口,亦即包含t的全部字母的窗口。

  3. 得到可行的窗口后,将start指针逐个右移,若得到的窗口依然可行,则更新最小窗口大小。

  4. 若窗口不再可行,则跳转至 2。

(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第6张图片
(LeetCode 3&11&15&18&76)滑动窗口(双指针)_第7张图片

你可能感兴趣的:(LeetCode)