【双指针】LeetCode 340. 至多包含 K 个不同字符的最长子串

发布时间 2023-05-24 09:50:07作者: Frodo1124

题目链接

340. 至多包含 K 个不同字符的最长子串

给你一个字符串 s 和一个整数 k ,请你找出 至多 包含 k 个 不同 字符的最长子串,并返回该子串的长度。

示例 1:

输入:s = "eceba", k = 2
输出:3
解释:满足题目要求的子串是 "ece" ,长度为 3 。

示例 2:

输入:s = "aa", k = 1
输出:2
解释:满足题目要求的子串是 "aa" ,长度为 2 。

思路

使用 HashMap 记录每种字符出现的次数,如果有字符出现次数从0变为1,则总字符数+1。如果总字符串超过了 \(k\),则向前移动左指针,直到小于等于 \(k\)

代码

class Solution {
    public int lengthOfLongestSubstringKDistinct(String s, int k) {
        if(k == 0){
            return 0;
        }
        HashMap<Character, Integer> hashMap = new HashMap<>();
        char[] cs = s.toCharArray();
        int result = 0;
        // 总字符种类
        int total = 0;

        int left = 0;
        int right = 0;

        while(right < cs.length){
            // 有新字符出现
            if(hashMap.getOrDefault(cs[right], 0) == 0){
                total++;
            }
            hashMap.put(cs[right], hashMap.getOrDefault(cs[right], 0) + 1);

            // 总字符种类 > k
            if(total > k){
                // 因为扩张了之后才 > k,所以不计入新字符,也就不用 right - left + 1
                result = Math.max(result, right - left);
                while(left < right && total > k){
                    hashMap.put(cs[left], hashMap.get(cs[left]) - 1);
                    if(hashMap.get(cs[left]) == 0){
                        total--;
                    }
                    left++;
                }
            }

            right++;
        }

        // 此时 right = cs.length,所以也不用 right - left + 1
        result = Math.max(result, right - left);

        return result;
    }
}