2.3.2 越长越合法

这类计数题通常先移动右端点扩大窗口;一旦达到合法状态,更长的窗口也会继续合法。

越长越合法的子数组计数图
越长越合法:固定右端点时,达到合法后可以统计所有更靠左起点形成的子数组。

1. Number Of Substrings Containing All Three Characters

 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
class Solution {
public:
    int numberOfSubstrings(string s) {
        int ans = 0;
        int cnt[3];
        int ok = 0;
        int l = 0, n = s.length();
        for(int r = 0; r < n; r++){
            if(cnt[s[r] - 'a'] == 0){
                ok++;
            }
            cnt[s[r] - 'a']++;

            while(l <= r && ok == 3){
                cnt[s[l] - 'a']--;
                if(cnt[s[l] - 'a'] == 0){
                    ok--;
                }
                l++;
            }

            ans += l;
        }
        return ans;
    }
};

2. Count Subarrays Where Max Element Appears At Least K Times

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
    long long countSubarrays(vector<int>& nums, int k) {
        int mx = ranges::max(nums);
        int cnt = 0;
        long long ans = 0;
        int l = 0, n = nums.size();
        for(int r = 0; r < n; r++){
            if(nums[r] == mx){
                cnt++;
            }

            while(cnt >= k){
                if(nums[l] == mx){
                    cnt--;
                }
                l++;
            }

            ans += l;
        }
        return ans;
    }
};

3. Count Substrings With K Frequency Characters I

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Solution {
public:
    int numberOfSubstrings(string s, int k) {
        int ans = 0;
        int cnt[27];
        int l = 0;
        for(char c : s){
            cnt[c - 'a']++;
            
            while(cnt[c - 'a'] >= k){
                cnt[s[l] - 'a']--;
                l++;
            }

            ans += l;
        }
        return ans;
    }
};

4. Count Complete Subarrays In An Array

 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 countCompleteSubarrays(vector<int>& nums) {
        set<int> s;
        int n = nums.size();
        for(int i=0; i<n; i++){
            s.insert(nums[i]);
        }
        int k = s.size();

        int l = 0;
        int ans = 0;
        map<int, int> m;
        for(int r = 0; r < n; r++){
            m[nums[r]]++;

            while(m.size() == k){
                m[nums[l]]--;
                if(m[nums[l]] == 0){
                    m.erase(nums[l]);
                }
                l++;
            }

            ans += l;
        }
        return ans;
    }
};

5. Count The Number Of Good Subarrays

 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
class Solution {
public:
    long long countGood(vector<int>& nums, int k) {
        long long ans = 0;
        map<int, int> cnt;
        int checked = 0;
        int l = 0, n = nums.size();
        for(int r=0; r<n; r++){
            cnt[nums[r]]++;
            if(cnt[nums[r]] > 0) 
                checked += cnt[nums[r]] - 1;

            while(checked >= k){
                cnt[nums[l]]--;
                checked -= cnt[nums[l]];
                if(cnt[nums[l]] == 0){
                    cnt.erase(nums[l]);
                }
                l++;
            }

            ans += l;
        }
        return ans;
    }
};

6. Count Substrings That Can Be Rearranged To Contain A String II

 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class Solution {
public:
    long long validSubstringCount(string word1, string word2) {
        int diff[26];
        for(char c : word2){
            diff[c - 'a']++;
        }

        int less = 0;
        for(int d : diff){
            if(d > 0) less++;
        }

        long long ans = 0;
        int l = 0, n = word1.length();
        for(int r = 0; r < n; r++){
            int i = word1[r] - 'a';
            diff[i]--;
            if(diff[i] == 0){
                less--;
            }

            while(less == 0){
                int i = word1[l] - 'a';
                if(diff[i] == 0) less++;
                diff[i]++;
                l++;
            }

            ans += l;
        }

        return ans;
    }
};

//下面是一开始超内存的:
class Solution {
public:
    long long validSubstringCount(string word1, string word2) {
        int k[27];
        int ksize = 0;
        for(char c : word2){
            if(k[c - 'a'] == 0) 
                ksize++;
            k[c - 'a']++;
        }

        long long ans = 0;
        int cnt[27];
        for(int i=0; i<27; i++){
            cnt[i] = 0;
        }
        set<int> ok;
        int l = 0, n = word1.length();
        for(int r = 0; r < n; r++){
            int i = word1[r] - 'a';
            cnt[i]++;
            if(k[i] != 0 && cnt[i] >= k[i]) ok.insert(i);

            while(l <= r && ok.size() >= ksize){
                int i = word1[l] - 'a';
                cnt[i]--;
                if(k[i] != 0 && cnt[i] < k[i]){
                    ok.erase(i);
                }
                l++;
            }

            ans += l;
        }
        return ans;
    }
};

/*
     用diff数组记录差异减少开销(记录出现个数的k和cnt数组就可以缩为一个diff数组),用一个变量
  存合法子数组数目,减少set<int>开销。
*/