一、定长滑动窗口

定长滑动窗口适合窗口长度固定的题目,核心是把每轮操作稳定拆成“入、更新、出”。

定长滑动窗口套路图
定长滑动窗口:每一轮先纳入右端点,再在窗口形成后更新答案,最后移出左端点。

1. Maximum Number Of Vowels In A Substring Of Given Length

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public:
    int maxVowels(string s, int k) {
        int ans = 0;
        int tmp = 0;
        for (int i = 0; s[i] != '\0'; i++) {
            //入
            if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' ||
                s[i] == 'u') {
                tmp++;
            }
            
            //更新
            if (tmp > ans)
                ans = tmp;

            //出
            int l = i - k + 1;
            if (l >= 0) {
                if (s[l] == 'a' || s[l] == 'e' || s[l] == 'i' || s[l] == 'o' ||
                    s[l] == 'u') {
                    tmp--;
                }
            }
        }
        return ans;
    }
};

2. Maximum Average Subarray I

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
    double findMaxAverage(vector<int>& nums, int k) {
        double tmp = 0;
        double ans = -1e10;
        int n = nums.size();
        for(int i=0; i<n; i++){
            //入
            tmp += nums[i];
            
            int l = i - k + 1;
            //更新
            if(l >= 0 &&  tmp > ans) ans = tmp;

            //出
            if(l >= 0) tmp -= nums[l];
        } 
        ans /= (1.0 * k);

        return ans;
    }
};

3. Number Of Sub Arrays Of Size K And Average Greater Than Or Equal To Threshold

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
    int numOfSubarrays(vector<int>& arr, int k, int threshold) {
        int sum = 0;
        int ans = 0;
        int t = threshold * k;
        int n = arr.size();
        for(int i=0; i<n; i++){
            //入
            sum += arr[i];

            int l = i - k + 1;
            if(l >= 0){
                //更新答案
                if(sum >= t) ans++;

                //出
                sum -= arr[l];
            }
        }  
        return ans;      
    }
};

4. K Radius Subarray Averages

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Solution {
public:
    vector<int> getAverages(vector<int>& nums, int k) {
        vector<int> ans;
        int n = nums.size();

        for(int i=0; i<min(n, k); i++){
            ans.push_back(-1);
        }

        long long sum = 0;
        for(int i=0; i<min(n, k); i++){
            sum += nums[i];
        }
        for(int i=k; i<n; i++){
            //入
            sum += nums[i];
            
            int l = i - 2 * k;
            //更新
            if(l >= 0) ans.push_back(sum / (2 * k + 1));

            //出
            if(l >= 0) sum -= nums[l];
        }
 
        while(ans.size() < n){
            ans.push_back(-1);
        }

        return ans;
    }
};

5. Minimum Recolors To Get K Consecutive Black Blocks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public:
    int minimumRecolors(string blocks, int k) {
        int ans = 0x3f3f3f3f;
        int op = 0;
        int n = blocks.length();
        for(int i=0; i<n; i++){
            //入
            if(blocks[i] == 'W') op++;

            int l = i - k + 1;
            if(l < 0) continue;
            //更新
            ans = min(ans, op);

            //出
            if(blocks[l] == 'W') op--;
        }
        return ans;
    }
};

6. Maximum Sum Of Almost Unique Subarray

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
public:
    long long maxSum(vector<int>& nums, int m, int k) {
        unordered_map<long long, int> map;
        long long sum = 0;
        long long ans = 0;
        int n = nums.size();
        for(int i=0; i<n; i++){
            //入
            map[nums[i]]++;
            sum += nums[i];

            int l = i - k + 1;
            if(l < 0) continue;
            //更新
            if(map.size() >= m){
                ans = max(ans, sum);
            }

            //出
            map[nums[l]]--;
            if(map[nums[l]] == 0) map.erase(nums[l]);
            sum -= nums[l];
        }
        return ans;
    }
};
/*
  1.这一题刚开始用set.size检查唯一元素个数,但在“出”的阶段出现问题,因为set无法得知元素重复
  个数,进而不能确定nums[l]是否应该从set中删去。用unordered_map记录元素出现次数即可。
  2. 一开始没考虑数据范围,没开long long
*/

7. Maximum Sum Of Distinct Subarrays With Length K

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public:
    long long maximumSubarraySum(vector<int>& nums, int k) {
        long long ans = 0;
        unordered_map<int, int> m;
        long long sum = 0;
        int n = nums.size();
        for(int i=0; i<n; i++){
            //入
            sum += nums[i];
            m[nums[i]]++;

            int l = i - k + 1;
            if(l < 0) continue;
            //更新
            if(m.size() == k) ans = max(ans, sum);

            //出
            sum -= nums[l];
            m[nums[l]]--;
            if(m[nums[l]] == 0) m.erase(nums[l]);
        }
        return ans;
    }
};

8. Maximum Points You Can Obtain From Cards

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
    int maxScore(vector<int>& cardPoints, int k) {
        int total = 0;
        int ans = 0x3f3f3f3f;   
        int sum = 0;
        int n = cardPoints.size();
        //原问题等价于选出点数和最小的连续n-k张牌
        for(int i=0; i<n; i++){
            total += cardPoints[i];
            //入
            sum += cardPoints[i];

            //更新
            int l = i - (n - k) + 1;
            if(l < 0) continue;
            ans = min(ans, sum);

            //出
            sum -= cardPoints[l];
        }
        //n-k == 0时,区间长为0,无法用滑动窗口
        if(k == n) ans = total;
        else ans = total - ans;
        return ans;
    }
};
/*
  这一题一开始的思路是从n-k的位置遍历到k的位置,用滑动窗口求最大和,但区间左端很难处理,卡了。
  将问题转换后就很好求了。
*/

9. Grumpy Bookstore Owner

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public:
    int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int minutes) {
        int sum[2]; //sum[0] 表示 grumpy[i] 为 0 时的和, sum[1] 同理
        int maxSum1 = -1;
        int n = customers.size();
        for(int i=0; i<n; i++){
            //入
            sum[grumpy[i]] += customers[i];

            //更新
            int l = i - minutes + 1;
            if(l < 0) continue;
            maxSum1 = max(maxSum1, sum[1]);

            //出
            if(grumpy[l]) sum[1] -= customers[l]; 
        }

        return sum[0] + maxSum1;
    }
};
/*
  一开始没有拆解清楚问题,没有什么思路。用O(n^2)过了。
  实际上,只需要分开grumpy为0和1的情况即可:
  1.grumpy为0,直接加
  2.grumpy为1,用滑动窗口算出窗口内最大和
  结果为二者相加
*/

10. Defuse The Bomb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//用右端点
class Solution {
public:
    vector<int> decrypt(vector<int>& code, int k) {
        int n = code.size();
        vector<int> ans(n);

        int r = k > 0 ? k + 1 : n;
        k = abs(k);
        int s = reduce(code.begin() + r - k, code.begin() + r, 0);
        /*
          reduce 计算左闭右开区间累加和,初始值为0(第三个参数)
        */
        for(int i=0; i<n; i++){
            ans[i] = s;
            s += code[r % n] - code[(r - k) % n];
            r++;
        }
        
        return ans;
    }
};

//用左端点
class Solution {
public:
    vector<int> decrypt(vector<int>& code, int k) {
        int n = code.size();
        vector<int> ans(n);

        int l = k > 0 ? 1 : n + k;
        k = abs(k);
        int s = reduce(code.begin() + l, code.begin() + l + k, 0);
        for(int i=0; i<n; i++){
            ans[i] = s;
            s += code[(l + k) % n] - code[l % n];
            l++;
        }
        
        return ans;
    }
};