> For the complete documentation index, see [llms.txt](https://junnie.gitbook.io/amazon-mock-interview/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://junnie.gitbook.io/amazon-mock-interview/onsite-ii/386longest-substring-with-at-most-k-distinct-characters.md).

# 386.Longest Substring with At Most K Distinct Characters

## 1.Description(Medium)

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

**Example**

For example, Given s =`"eceba"`,`k = 3`,

T is`"eceb"`which its length is`4`.

[**Challenge**](https://www.lintcode.com/en/problem/longest-substring-with-at-most-k-distinct-characters/#challenge)

O(n), n is the size of the string*s*.

[**Tags**](https://www.lintcode.com/en/problem/longest-substring-with-at-most-k-distinct-characters/#tags)

[Two Pointers](https://www.lintcode.com/tag/two-pointers/) [Hash Table](https://www.lintcode.com/tag/hash-table/) [String](https://www.lintcode.com/tag/string/) [LintCode Copyright](https://www.lintcode.com/tag/lintcode-copyright/)

## 2.Code

<http://blog.csdn.net/whuwangyi/article/details/42451289>

<http://www.cnblogs.com/grandyang/p/5185561.html>

<http://www.cnblogs.com/grandyang/p/5351347.html>

Version 1: hashmap里记录char和char出现的次数。

用哈希表来做，哈希表记录每个字符的出现次数

Given S = “eceba”,k=2

T is “ece” which its length is 3.

然后如果哈希表中的映射数量超过k个的时候，我们需要删掉一个映射，比如此时哈希表中e有2个，c有1个，此时把b也存入了哈希表，那么就有三对映射了，这时我们的left是0，先从e开始，映射值减1，此时e还有1个，不删除，left自增1。这是哈希表里还有三对映射，此时left是1，那么到c了，映射值减1，此时e映射为0，将e从哈希表中删除，left自增1，

然后我们更新结果为i - left + 1，(每次遍历一个char的时候都更新)

以此类推直至遍历完整个字符串，

```
public int lengthOfLongestSubstringKDistinct(String s, int k) {
        if(s==null || s.length()==0 || k<=0){
            return 0;
        }
        HashMap<Character,Integer> map=new HashMap<>();
        int maxlen=0;
        int start=0;
        for(int i=0;i<s.length();i++){
            char current=s.charAt(i);
            if(map.containsKey(current)){
                map.put(current,map.get(current)+1);
            }
            else{
                map.put(current,1);
                while(map.size()>k){
                    char left=s.charAt(start);
                    int count=map.get(left);
                    if(count>1){
                        map.put(left, count-1);
                    }else{
                        map.remove(left);
                    }
                    start++;
                }
            }
            maxlen=Math.max(maxlen, i-start+1);
        }
        return maxlen;
    }
```

Version 2: hashmap 存放的是char和最后出现的坐标。

我们还可以映射每个字符最新的坐标，比如题目中的例子"eceba"，遇到第一个e，映射其坐标0，遇到c，映射其坐标1，遇到第二个e时，映射其坐标2，当遇到b时，映射其坐标3，每次我们都判断当前哈希表中的映射数，如果大于k的时候，那么我们需要删掉一个映射，我们还是从left=0时开始向右找，

我们看每个字符在哈希表中的映射值是否等于当前坐标left，

比如第一个e，哈希表此时映射值为2，不等于left的0，

那么left自增1，遇到c的时候，哈希表中c的映射值是1，和此时的left相同，那么我们把c删掉，left自增1，再更新结果，以此类推直至遍历完整个字符串，

```
public int lengthOfLongestSubstringKDistinct2(String s, int k){
        if(s==null || s.length()==0 || k<=0){
            return 0;
        }
        HashMap<Character,Integer> map=new HashMap<>();
        int maxlen=0;
        int start=0;
        for(int i=0;i<s.length();i++){
            char current=s.charAt(i);
            if(map.containsKey(current)){
                map.put(current, i);
            }else{
                map.put(current,i);
                while(map.size()>k){
                    char left=s.charAt(start);
                    if(map.get(left)!=start){
                        start++;
                    }else{
                        map.remove(left);
                        start++;
                    }
                }
            }
            maxlen=Math.max(maxlen, i-start+1);
        }
        return maxlen;
    }
```
