Longest Substring with At Most Two Distinct Characters

最新思路解法:https://yanjia.me/zh/2018/12/...

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.

哈希表法

复杂度

时间 O(N) 空间 O(1)

思路

我们遍历字符串时用一个哈希表,但这个哈希表只记录两个东西,一个字母和它上次出现的时的下标,另一个字母和它上次出现时候的下标。这样,如果新来的字母已经存在与表中,或者表中现在少于两个字母,就没关系,我们只要更新下它新的下标就行了。如果不存在于表中,则找出表中两个字母中,靠前面的那个,然后把这个较前的字母去掉,再加入这个新的字母。这样,我们就能维护一个窗口,保证其中只有两种字母。每次加入新字母时,说明上一个子串已经达到最长了,这时候我们判断下时候要更新全局最长子串就行了。这个通过用哈希表记录字母上次出现的下标,来维护一个窗口的方法也可以用于Longest Substring Without Repeating Characters

注意

  • 遍历完之后还要一个额外判断最长子串的代码来处理最后一个子串
  • 加入新字母后,新子串的起始位置是被除去字母最后一次出现位置的后一个

代码

Java

public class Solution {
    public int lengthOfLongestSubstringTwoDistinct(String s) {
        String longestSubstr = "";
        int maxLength = 0, start = 0;
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            // 如果表中已经有两个字母,且遇到了表中没有的新字母时,加入新字母
            if(map.size() >= 2 && !map.containsKey(c)){
                int leftMost = s.length();
                // 先计算出新字母之前的子串的长度
                if(i - start > maxLength){
                    longestSubstr = s.substring(start, i);
                    maxLength = i - start;
                }
                // 找出哪个字母更靠前,将其去除
                for(Character key : map.keySet()){
                    if(map.get(key)<leftMost){
                        leftMost = map.get(key);
                    }
                }
                // 更新加入新字母后子串的起始位置,这个位置是被去除字母最后一次出现的位置加1
                start = leftMost + 1;
                map.remove(s.charAt(leftMost));
            }
            // 更新该字母下标
            map.put(c, i);
        }
        // 处理最后一个子串
        if(s.length() - start > maxLength){
            longestSubstr = s.substring(start, s.length());
            maxLength = s.length() - start;
        }
        return maxLength;
    }
}

Go

func lengthOfLongestSubstringTwoDistinct(s string) int {
    chars := map[byte]int{}
    start := 0
    maxLength := 0
    for index := 0; index < len(s); index++ {
        char := s[index]
        if _, ok := chars[char]; !ok && len(chars) >= 2 {
            minIndex := len(s)
            for _, value := range chars {
                if value < minIndex {
                    minIndex = value
                }
            }
            start = minIndex + 1
            delete(chars, s[minIndex])
        }
        length := index - start + 1
        if maxLength < length {
            maxLength = length
        }
        chars[char] = index
    }
    return maxLength
}

后续 Follow Up

Q:如果可以有k个distinct字母,怎么做?
A:将上题中的2换成k就行了。当HashMap的大小大于k时,我们才将最早出现的字母移去。


ethannnli
858 声望360 粉丝