滑动窗口解决子串包含指定字符数问题整理

判断两个字符串s和t,s的子串中能够包含t中所有字符的子串数

我的解法:

其实也就是求word1中包含word2中所有字符的子串数

class Solution {
    public long validSubstringCount(String word1, String word2) {
        if (word1.length() < word2.length()) {
            return 0;
        }
        long res = 0;
        //记录两个字符串中字符的数量
        int[] record1 = new int[26];
        int[] record2 = new int[26];
        //统计word2中每个字符出现的次数
        for(char c : word2.toCharArray()) {
            record2[c - 'a']++;
        }

        int chartypes = 0;
        //统计word2中字符的种类,用来记录在滑动窗口移动时子串中包含的字符种类符合word2要求
        for (int i : record2) { 
            if (i != 0) {
                chartypes++;
            }
        }

        char[] s = word1.toCharArray();
        // int l, r;
        for (int l = 0, r = 0; r < s.length; r++) {
            char c = s[r];
            record1[c - 'a']++;
            //子串中c字符的数量满足word2的需求
            if (record1[c - 'a'] == record2[c - 'a']) {
                chartypes--;
            }
            //每种字符的数量都满足要求了
            if (chartypes == 0) {
                res += s.length - r;
                //左移窗口直到不满足word2的需求
                while (record1[s[l] - 'a'] == 0 || record1[s[l] - 'a'] > record2[s[l] - 'a']) {
                    if (record1[s[l] - 'a'] != 0) {
                        record1[s[l] - 'a']--;
                    }
                    res += s.length - r; 
                    l++;
                }
                record1[s[l] - 'a']--;
                l++;
                chartypes++;
            }
        }
        return res;
    }
}

**灵神方法:**也可以创建一个数组进行滑动窗口

class Solution {
    public long validSubstringCount(String S, String T) {
        if (S.length() < T.length()) {
            return 0;
        }

        char[] s = S.toCharArray();
        char[] t = T.toCharArray();
        int[] cnt = new int[26]; // t 的字母出现次数与 s 的字母出现次数之差
        for (char b : t) {
            cnt[b - 'a']++;
        }
        int less = 0; // 统计窗口内有多少个字母的出现次数比 t 的少
        for (int c : cnt) {
            if (c > 0) {
                less++;
            }
        }

        long ans = 0;
        int left = 0;
        for (char b : s) {
            if (--cnt[b - 'a'] == 0) {
                // 窗口内 b 的出现次数和 t 一样
                less--;
            }
            while (less == 0) { // 窗口符合要求
                if (cnt[s[left++] - 'a']++ == 0) {
                    // s[left] 移出窗口后,窗口内 s[left] 的出现次数比 t 的少
                    less++;
                }
            }
            ans += left;
        }
        return ans;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值