Sliding window question set 1

Keywords: Linux MySQL Docker Cpp

1 sliding window

priority_queue is often used

0480 sliding window median

1 topic

https://leetcode-cn.com/problems/sliding-window-median/

2 problem solving ideas

  • 1 use a multiset to maintain the current window,
    • 1.1 do not use priority_ The element cannot be deleted because of the queue
    • 1.2 the reason why map/set is not used cannot contain duplicate elements
  • 2 for windows, maintain a median pointer. Note that there are only several situations when the median pointer moves in each window
    • 2.1 left, right, stationary
    • 2.2 classified discussion can be cleared
class Solution {
public:
    vector<double> medianSlidingWindow(vector<int>& nums, int k) {
        long long n = nums.size();
        std::multiset<long long, std::less<long long>> mySet(nums.begin(), nums.begin() + k);

        vector<double> res;
        multiset<long long>::iterator mid = mySet.begin();
        std::advance(mid, (k-1)/2);

        for(long long i = k; i <= n; ++i) {
            res.emplace_back((*mid + *next(mid, 1 - k%2))*1.0L/2);
            if(i == n) break;

            mySet.insert(nums[i]);
            if (nums[i] > *mid && nums[i - k] < *mid) {
                mid++;
                mySet.erase(mySet.lower_bound(nums[i-k]));
                continue;
                // std::advance(mid, 1);
            }

            if (nums[i] < *mid && nums[i - k] > *mid) {
                mid--;
                mySet.erase(mySet.lower_bound(nums[i-k]));
                continue;
                // std::advance(mid, -1);
            }
            // 7 3 7 7 4, k = 4
            // 7 8 7 7 4, k = 4
            if(nums[i-k] == *mid) {
                if(nums[i] >= *mid)  ++mid;
                else {
                    if(*prev(mid) != *mid) {
                        --mid;
                    }
                }
                mySet.erase(mySet.lower_bound(nums[i-k]));
                continue;
            } 

            if(nums[i] == *mid) {// It is equivalent to inserting a number larger than mid in front of mid
                if(nums[i-k] <= *mid)  ++mid;
                mySet.erase(mySet.lower_bound(nums[i-k]));
                continue;
            }
        }
        return res;
    }
};

Number of subarrays of 0992 k different elements

1 topic

https://leetcode-cn.com/problems/subarrays-with-k-different-integers/submissions/

2 problem solving ideas

  • 1. Normal thinking:
    • 1.1 first, the window is required, that is [st, ed]. Then ensure that the window contains k different variables at any time, and then sum the number of subarrays ending in ED
    • 1.2 the number of subarrays of the window [st, ed] ending with ED is calculated. Assuming k=2 and the window is 1,2,1,2, then with ED as the end, St moves forward until the number of different elements in the window decreases to k-1. At this time, St moves to the second 2 for a total of 3 times, that is, the number of subarrays containing K different variables ending with ED is 3.
    • 1.3 the complexity lies in how to judge the number of different elements in the window. We use the classical space for time method (because the value of all elements will not be greater than the length of the array itself), and use freq[val] to record the number of val occurrences. What if the length is unlimited? Then you need to use unordered_map to record the occurrence times of all elements in the current window, and then st needs to traverse this map every time it moves to judge the number of different elements in the current window. Then the overall complexity is: o(n * k * k)
  • 2 official explanation:
    • 2.1 the number of subarrays with different elements K is: the number of subarrays with different elements up to K - the number of subarrays with different elements up to k-1. Then the problem turns to finding the number of subarrays of an array with different elements up to K
    • 2.2 solution: it is still the idea of sliding the window, and always keep the number of the most elements in the window no more than K (the method is to move ed each time until it exceeds K for the first time, and then move st until it is less than k). Then for each ed, ed - st is the number of sub arrays with ED as the end of the window and corresponding different elements no more than K. for example: (official example):

Understand with specific examples: the sub interval [1, 3, 2, 3] containing at most three different integers (the double pointer algorithm is to let the right boundary go to the far right on the premise that the left boundary is fixed). At present, it can be determined that the sub interval starting from 1 satisfying at most three different integers includes [1], [1, 3], [1, 3, 2], [1, 3, 2, 3].

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& nums, int k) {
        return maxSubArrayNumForKDiff(nums, k) - maxSubArrayNumForKDiff(nums, k - 1);

    }

    int maxSubArrayNumForKDiff(vector<int>& nums, int k) {
        vector<int> freq(nums.size() + 1);
        long long res = 0;
        int st = 0;
        int ed = 0;
        int curCnt = 0;
        while(ed < nums.size()) {
            // Find the number of subarrays of up to k different elements corresponding to each ed
            if(freq[nums[ed]] == 0) {
                curCnt ++;
            }
            freq[nums[ed]]++;
            ++ed;

            // Reduce the window to k-1 for the first time
            while(curCnt > k) {
                freq[nums[st]]--;
                if(freq[nums[st]] == 0) {
                    curCnt--;
                }
                ++st;
            }
            res += ed - st;
        }
        return res;
    }
};

0904 number of complete fruits

1 topic

https://leetcode-cn.com/problems/fruit-into-baskets/

2 problem solving ideas

  • 1. Normal thinking: (at 0904) https://leetcode-cn.com/problems/fruit-into-baskets/ Implementation)
    • 1.1 first, the window is required, that is [st, ed]. Then ensure that the window contains k different variables at any time, and then sum the number of subarrays ending in ED
    • 1.2 the number of subarrays of the window [st, ed] ending with ED is calculated. Assuming k=2 and the window is 1,2,1,2, then with ED as the end, St moves forward until the number of different elements in the window decreases to k-1. At this time, St moves to the second 2 for a total of 3 times, that is, the number of subarrays containing K different variables ending with ED is 3.
    • 1.3 the complexity lies in how to judge the number of different elements in the window. We use the classical space for time method (because the value of all elements will not be greater than the length of the array itself), and use freq[val] to record the number of val occurrences. What if the length is unlimited? Then you need to use unordered_map to record the occurrence times of all elements in the current window, and then st needs to traverse this map every time it moves to judge the number of different elements in the current window. Then the overall complexity is: o(n * k * (log k)) = o(n)
  • 2 official explanation:
    • 2.1 the number of subarrays with different elements K is: the number of subarrays with different elements up to K - the number of subarrays with different elements up to k-1. Then the problem turns to finding the number of subarrays of an array with different elements up to K
    • 2.2 solution: it is still the idea of sliding the window, and always keep the number of the most elements in the window no more than K (the method is to move ed each time until it exceeds K for the first time, and then move st until it is less than k). Then for each ed, ed - st is the number of sub arrays with ED as the end of the window and corresponding different elements no more than K. for example: (official example):

Understand with specific examples: the sub interval [1, 3, 2, 3] containing at most three different integers (the double pointer algorithm is to let the right boundary go to the far right on the premise that the left boundary is fixed). At present, it can be determined that the sub interval starting from 1 satisfying at most three different integers includes [1], [1, 3], [1, 3, 2], [1, 3, 2, 3].

class Solution {
public:
    int totalFruit(vector<int>& fruits) {
        if(fruits.size() <= 1) {
            return 1;
        }

        // Array length with different elements up to 2
        int res = 0;
        int st = 0;
        int ed = 0;
        int curCnt = 0;
        map<int, int> freq;
        bool stNotMov = true;
        while(ed < fruits.size()) {
            while(freq.size() <= 2 && ed < fruits.size()) {
                if(freq.find(fruits[ed]) == freq.end()) {
                    curCnt++;
                }
                freq[fruits[ed]]++;
                ed++;
            }
            
            if(!stNotMov && ed != fruits.size()) {
                res = std::max(res, ed - st - 1);
            } else  {
                if(freq.size() == 3) {
                    res = std::max(res, ed - st - 1);
                } else {
                    res = std::max(res, ed - st);
                }
                
            }
            
            while(freq.size() > 2) {
                freq[fruits[st]]--;
                if(freq[fruits[st]] == 0) {
                    freq.erase(freq.find(fruits[st]));
                }
                ++st;
                stNotMov = false;
            }
        }
        return res;
    }
};

0995 minimum number of executions: flip k at a time to make the array all 1

1 topic

https://leetcode-cn.com/problems/minimum-number-of-k-consecutive-bit-flips/

2 problem solving ideas

  • 1. Normal thinking: there are always K windows to simulate the flipping process. Since the first number after flipping needs to be found in the window, the complexity is O (k), so the total complexity is O(n*k)
  • 2 official solution: use the difference array diff,diff[i] indicates how many times nums[i] has flipped more than nums[i-1], then the current total number of flipping times is: sum(diff[i]). For nums[i], sum(diff[i])%2 is 0, indicating that nums[i] needs to be flipped.
class Solution {
public:
    int minKBitFlips(vector<int>& nums, int k) {
        vector<long long> preSum = {0};
        for(long long num : nums) {
            preSum.emplace_back(preSum.back() + num);
        }

        long long st = 0;
        long long ed = st + k - 1;
        long long n = nums.size();
        long long res = 0;

        vector<long long> diff(n+1);
        long long flipCnt = 0;
        // while(st < n - k + 1) {
            // The simulation will time out
            // if(nums[st] == 1) {
            //     ++st;
            //     continue;
            // }
            // int newSt = flipKBit(nums, k, st, preSum);
            // if(newSt == -1) {
            //     st = st + k;
            // } else {
            //     st = newSt;
            //     res += 1;
            // }
        // }
        // if(find(nums.end() - k, nums.end(), 0) == (nums.end())) {
        //     return res;
        // } 

        while(st < n) {
            // The query array is used to record the number of times each element should be flipped
            // This inspires us to use the idea of difference fraction group to calculate the number of times the current number needs to be flipped. We can maintain a differential array \ textit{diff}diff, where \ textit{diff}[i]diff[i] represents two adjacent elements 
            // \For the difference of turnover times between textit{nums}[i-1]nums[i − 1] and \ textit{nums}[i]nums[i], for the interval [l,r][l,r], adding 11 to all its elements will only affect the difference values at ll and r+1r+1,
            // Therefore, the \ textit{diff}[l]diff[l] increases by 11 and the \ textit{diff}[r+1]diff[r+1] decreases by 11.
            flipCnt += diff[st];
            if((flipCnt + nums[st]) % 2 == 0) {
                if(st + k > n) {
                    return -1;
                }
                diff[st] ++;
                diff[st + k] --;
                res++;
                flipCnt ++;
            }
            ++st;
        }
        return res;
    }

    // Flip kbit and return the subscript in the first flip window whose value after inversion is not equal to 1. Otherwise, return - 1
    int flipKBit(vector<int>& nums, int k, int st, vector<int>& preSum) {
        int firstNot1 = INT_MAX;
        // Complexity requiring O(k) time
        bool needFlip = find(nums.begin() + st, nums.begin() + st + k, 0) != (nums.begin() + st + k);
        // Using prefix and optimization, because the array is flipped in the field, the corresponding prefix and will be changed, so this method is not feasible
        // bool needFlip = ((preSum[st + k] - preSum[st]) != k);

        // for(int i = st; i < k; ++i) {
        //     if(nums[st + i] != 1) {
        //         needFlip = true;
        //     }
        // }
        if(needFlip) {
            for(int i = 0; i < k; ++i) {
                nums[st + i] = abs(nums[st + i] - 1);
                if(nums[st + i] != 1) {
                    firstNot1 = min(firstNot1, st + i);
                }
            }
            return firstNot1 > nums.size() ? st + k : firstNot1 ;
        }
        

        return -1;
    }
};

1696 maximum results

1 topic

https://leetcode-cn.com/problems/jump-game-vi/submissions/

2 problem solving ideas

  • 1 using dynamic programming: dp[i] represents the maximum benefit of jumping to I, as follows: search the first k subscripts of I
        // o(n * k) solution
        dp[0] = 0;
        dp[1] = nums[0];
        for(int i = 1; i < nums.size() + 1; ++i) {
            for(int m = 1; m < k + 1 && i - m > 0; ++m) {
                dp[i] = max(dp[i], dp[i-m] + nums[i-1]);
            }
        }
  • 2. To optimize the above scheme of searching the first k subscripts, we use the priority queue to maintain the largest previous hop in the first k:
    • Change the above O(n*k) to O(n*logk) because the push operation of maxHeap is the complexity of logN
class Solution {
public:
    struct number {
        long long idx = 0;
        long long val = 0;
        number(long long idx, long long val): idx(idx), val(val) {};

        // sort descending
        bool  operator<(const number& b) const {return this->val < b.val;}
    };
    int maxResult(vector<int>& nums, int k) {
        vector<long long> dp(nums.size() + 1, INT_MIN);
        // o(n * k) solution
        dp[0] = 0;
        dp[1] = nums[0];
        // for(int i = 1; i < nums.size() + 1; ++i) {
        //     for(int m = 1; m < k + 1 && i - m > 0; ++m) {
        //         dp[i] = max(dp[i], dp[i-m] + nums[i-1]);
        //     }
        // }

        std::priority_queue<number, std::vector<number>, std::less<number>> maxHeap;
        maxHeap.push({1, nums[0]});
        // Using heap Optimization:
        for(int i = 2; i < nums.size() + 1; ++i) {
            while(maxHeap.top().idx < i - k) {
                maxHeap.pop();
            }

            dp[i] =  maxHeap.top().val + nums[i - 1];
            maxHeap.push({i, dp[i]});
            
            // for(int m = 1; m < k + 1 && i - m > 0; ++m) {
            //     dp[i] = max(dp[i], dp[i-m] + nums[i-1]);
            // }
        }
        
        return dp[nums.size()];

    }
};

summary

Maximum value of sliding window: maxHeap can be used to maintain the complexity logk

Posted by teongkia on Wed, 17 Nov 2021 23:36:42 -0800