Leetcode - Longest Substring with At Most Two Distinct Characters

Given a string, find the length of the longest substring T that contains at most 2 distinct characters.

For example, Given s = “eceba”,

T is "ece" which its length is 3.
[分析] 滑动窗口法,窗口内始终仅保留至多两个相异字符组成的字符串。实现时有两个问题需要考虑:1)何时更新窗口的左边界 2)如何更新窗口的左边界。问题1简单,当前字符不在窗口内且窗口内已包含两种字符。问题2最关键,想清楚了该问题也就解决了。当前窗口的左边界字符必然是要被删除的,但需要全部清除窗口内所有该字符吗?不见得,考虑这个例子abaccc, 遍历到第一个c时若将a全部清除则求得的长度是3,但实际上应该是4。正确的做法是找到窗口内最后位置最靠左的字符,设其最末位置为mostLeftEndPos, 窗口的新左边界则为mostLeftEndPos + 1,
这种做法的正确性在于保证更新时清除的字符串最短。
参考博客中还给出了扩展题,至多保留K个相异字符。更多请阅读原文: http://blog.csdn.net/whuwangyi/article/details/42451289

public class LongestSubstringWithAtMost2DistinctChars {
    @Test
    public void testSolution() {
        Solution obj = new Solution();
        Assert.assertEquals(4, obj.longest2("abaa"));
        Assert.assertEquals(4, obj.longest2("abaccc"));
        Assert.assertEquals(4, obj.longestK("abaa", 2));
        Assert.assertEquals(4, obj.longestK("abaccc", 2));
        Assert.assertEquals(6, obj.longestK("abacccd", 3));
    }
}

class Solution {
    public int longest2(String s) {
        if (s == null || s.length() == 0)
            return 0;
        int start = 0;
        int N = s.length();
        HashMap<Character, Integer> map = new HashMap<Character, Integer>(2);
        map.put(s.charAt(0), 0);
        int max = 1;
        for (int i = 1; i < N; i++) {
            char c = s.charAt(i);
            if (!map.containsKey(c) && map.size() == 2) {
                // update left bound of sliding window
                int mostLeftEndPos = i - 1;
                char toBeRemoved = ' ';
                for (Character key : map.keySet()) {
                    if (map.get(key) < mostLeftEndPos) {
                        mostLeftEndPos = map.get(key);
                        toBeRemoved = key;
                    }
                }
                start = mostLeftEndPos + 1;
                map.remove(toBeRemoved);
            }
            map.put(c, i);
            max = Math.max(max, i - start + 1);
        }
        return max;
    }
    //k 比较大时遍历map就比较低效,不如从start开始寻找第一个最后位置跑出窗口的字符
    public int longestK(String s, int k) {
        if (s == null || s.length() == 0)
            return 0;
        int N = s.length();
        int start = 0;
        int max = 0;
        
        // c: letter; value: the number of occurrences.  
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        for (int i = 0; i < N; i++) {
            char c = s.charAt(i);
            if (map.containsKey(c)) {
                map.put(c, map.get(c) + 1);
            } else {
                map.put(c, 1);
                while (map.size() > k) {
                    char startChar = s.charAt(start++);
                    int count = map.get(startChar);
                    if (count > 1) {
                        map.put(c, count - 1);
                    } else {
                        map.remove(startChar);
                    }
                }
           }
            max = Math.max(max, i - start + 1);
        }
        return max;
    }
}

你可能感兴趣的:(substring)