Question

Formatted question description: https://leetcode.ca/all/159.html

 159	Longest Substring with At Most Two Distinct Characters

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

 Example 1:

 Input: "eceba"
 Output: 3
 Explanation: tis "ece" which its length is 3.

 Example 2:

 Input: "ccaabbb"
 Output: 5
 Explanation: tis "aabbb" which its length is 5.

 @tag-string
 @tag-2pointers

Algorithm

Use HashMap to do it, HashMap records the number of occurrences of each character,

Then if the number of mappings in HashMap exceeds two, one mapping needs to be deleted here.

For example, there are 2 e in the HashMap and 1 c in the HashMap. At this time, b is also stored in the HashMap, then there are three pairs of mappings. At this time, left is 0, and the mapping value is reduced by 1. There is one more e, do not delete it, and left is incremented by 1. At this time, there are three pairs of mappings in the HashMap. At this time, left is 1, then c is reached, and the mapping value is reduced by 1. At this time, e is mapped to 0, e is deleted from the HashMap, left is incremented by 1, and the result is updated to i - left + 1,

And so on until the entire string is traversed.

Code

Java

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Longest_Substring_with_At_Most_Two_Distinct_Characters {

    public static void main(String[] args) {
        Longest_Substring_with_At_Most_Two_Distinct_Characters out = new Longest_Substring_with_At_Most_Two_Distinct_Characters();
        Solution s = out.new Solution();

        System.out.println(s.lengthOfLongestSubstringTwoDistinct("eceba"));
        System.out.println(s.lengthOfLongestSubstringTwoDistinct("ccaabbb"));
    }

    // refer to:
    //       Longest_Substring_with_At_Most_K_Distinct_Characters

    public class Solution {
        /**
         * @param s: a string
         * @return: the length of the longest substring T that contains at most 2 distinct characters
         */
        public int lengthOfLongestSubstringTwoDistinct(String s) {
            if (s == null || s.length() == 0) {
                return 0;
            }

            // char => its count in window
            Map<Character, Integer> map = new HashMap<>();
            int maxLen = 0;
            int left = 0;
            int right = 0;

            while (right < s.length()) {
                char c = s.charAt(right);
                if (map.containsKey(c)) {
                    map.put(c, map.get(c) + 1);
                } else {
                    map.put(c, 1);
                }

                // if distinct chars more than k
                if (map.size() > 2) {
                    maxLen = Math.max(maxLen, right - left);

                    // shrink the window size
                    while (map.size() > 2) { // can be done by another counter variable
                        char leftChar = s.charAt(left);
                        int freq = map.get(leftChar);
                        if (freq == 1) {
                            map.remove(leftChar); // @note: remove by key
                        } else {
                            map.put(leftChar, freq - 1);
                        }
                        left++;
                    }
                }

                right++;
            }

            // @note: final check
            if (left < s.length()) {
                maxLen = Math.max(maxLen, right - left);
            }

            return maxLen;
        }
    }

    public class Solution_arrayAsMap {

        public int lengthOfLongestSubstringTwoDistinct(String s) {

            int[] countMap = new int[256];
            Set<Character> hs = new HashSet<>();

            int result = 0;
            int left = 0;
            int right = 0;

            while (right < s.length()) {

                char c = s.charAt(right);
                countMap[c]++;
                hs.add(c);

                if (hs.size() > 2) {

                    result = Math.max(result, right - left);

                    while (hs.size() > 2) {
                        if (--countMap[s.charAt(left)] == 0) {
                            hs.remove(s.charAt(left));
                        }
                        left++;
                    }
                }

                right++;
            }

            // @note: final check
            if (left < s.length()) {
                result = Math.max(result, right - left);
            }

            return result;
        }

    }
}

All Problems

All Solutions