美文网首页算法
1.滑动窗口

1.滑动窗口

作者: 云殊_Tech | 来源:发表于2020-12-22 00:30 被阅读0次

    滑动窗口笔记 Sliding Window Notes

    Table of Contents




    Intro

    This technique shows how a nested for loop in some problems can be converted to a single for loop to reduce the time complexity.


    Tipps:

    • 滑动窗口是一个子数组(连续的)
    • 滑动窗口的长度可以固定,也可以不固定
    • left pointer <= right pointer

    Examples

    <a id ="exa1" href ="https://leetcode-cn.com/problems/minimum-adjacent-swaps-for-k-consecutive-ones/">5624. Minimum Adjacent Swaps for K Consecutive Ones</a>

    You are given an integer array nums, and an integer k. nums comprises of only 0's and 1's. In one move, you can choose two adjacent indices and swap their values.

    Return the minimum number of moves required so that nums has k consecutive 1's.

    Example 1:
    Input: nums = [1,0,0,1,0,1], k = 2
    Output: 1
    Explanation: In 1 move, nums could be [1,0,0,0,1,1] and have 2 consecutive 1's.
    
    Example 2:
    Input: nums = [1,0,0,0,0,0,1,1], k = 3
    Output: 5
    Explanation: In 5 moves, the leftmost 1 can be shifted right until nums = [0,0,0,0,0,1,1,1].
    
    Example 3:
    Input: nums = [1,1,0,1], k = 2
    Output: 0
    Explanation: nums already has 2 consecutive 1's.
    
    Constraints:
    1 <= nums.length <= 105
    nums[i] is 0 or 1.
    1 <= k <= sum(nums)
    
    from typing import List
    class Solution:
        def minMoves(self, nums: List[int], k: int) -> int:
            if k<=1: return 0
    
            #记录所有1的index
            one_ind = []
            length = len(nums)
            for i in range(length):
                if nums[i] == 1:
                    one_ind.append(i)
    
            # sliding window
            # left, right, mid
            # 不断寻找下一个这样的窗口: 窗口里面恰有k个1,
            # 并记录每个窗口对应的move数, 最后返回最小的move数
    
            # 移动left,right至第一个1处
            right = left = one_ind[0]
    
            # mid为k个1中正中间的那个1,mid左边的0应向左移出窗口,mid右边的0应向右移出窗口
            mid = k // 2   # 第$mid+1$个1为中间的1
            l_ind = 0  #! 记录left是第几个1,则index of mid = l_ind + mid 
    
            count = 1   #计数当前窗口1的数量
    
            ret = float("inf")
            while right < length-1:
    
                right += 1
                if nums[right] == 0: continue
    
                count +=1
                # 这里意味着我们找到了下一个1,检查窗口是否已有k个1
    
                # 若找到了k个1,则记录当前窗口需要的move数
                if count == k:
                    # 确定mid_ind:
                    mid_ind = one_ind[l_ind+mid]
    
                    # mid及mid左边的0向左移除窗口,mid右边的0向右移除窗口
                    # 算法: 从left到right遍历, 记录每个0当前的index1和移除窗口后的index2,
                    # 则这个0的交换次数 = |index1-index2|
    
                    # indices := [(index1,index2)...]: a list of two indices of each 0
                    # temp1 := left,left+1,left+2... temp2 = right,right-1,right-2
                    # 例如: 110010011, k=5 => 001111100, 左边的0移除后的index为0,1;右边的为7,8
                    temp1 = left
                    temp2 = right
                    indices=[]
    
                    for i in range(left,mid_ind):
                        if nums[i] ==0:
                            indices.append((i,temp1))
                            temp1 += 1
                    for i in range(right,mid_ind,-1):
                        if nums[i] == 0:
                            indices.append((i,temp2))
                            temp2 -= 1
                    # 求move数
                    move_num = sum([abs(a-b) for (a,b) in indices])
                    
                    # 更新ret
                    ret = min(ret,move_num)
    
                    #! 此时向右移动right已无意义,应将left右移至下一个1处
                    l_ind +=1
                    left = one_ind[l_ind]
    
                    count -= 1
    
                # 若还不够k个1,则继续寻找
    
            return ret
    

    相关文章

      网友评论

        本文标题:1.滑动窗口

        本文链接:https://www.haomeiwen.com/subject/taoknktx.html