classSolution {publicintlengthOfLongestSubstringKDistinct(String s,int k) {if (s ==null||s.length() ==0|| k ==0) {return0; }HashMap<Character,Integer> count =newHashMap<>();int n =s.length();int firstIdx =0;char[] chs =s.toCharArray();int longest =0;for (int i =0; i < n; i++) {count.put(chs[i],count.getOrDefault(chs[i],0) +1);while (count.size() > k) {count.put(chs[firstIdx],count.get(chs[firstIdx]) -1);if (count.get(chs[firstIdx]) ==0) {count.remove(chs[firstIdx]); } firstIdx++; } longest =Math.max(longest, i - firstIdx +1); }return longest; }}
Follow Up
The interviewer may say that the string is given as a steam. In this situation, we can't maintain a "left pointer" as the classical O(n) hashmap solution.
Instead of recording each char's count, we keep track of char's last occurrence. If you consider k as constant, it is also a O(n) algorithm.
inWindow keeps track of each char in window and its last occurrence position
TreeMap + HashMap - O(nlogk)
publicclassSolution {publicintlengthOfLongestSubstringKDistinct(String str,int k) {if (str ==null||str.isEmpty() || k ==0) {return0; }TreeMap<Integer,Character> lastOccurrence =newTreeMap<>();Map<Character,Integer> inWindow =newHashMap<>();int j =0;int max =1;for (int i =0; i <str.length(); i++) {char in =str.charAt(i);while (inWindow.size() == k &&!inWindow.containsKey(in)) {int first =lastOccurrence.firstKey();char out =lastOccurrence.get(first);inWindow.remove(out);lastOccurrence.remove(first); j = first +1; }//update or add in's position in both mapsif (inWindow.containsKey(in)) {lastOccurrence.remove(inWindow.get(in)); }inWindow.put(in, i);lastOccurrence.put(i, in); max =Math.max(max, i - j +1); }return max; } }
Another Implementation based on LinkedHashMap - O(n)
classSolution {publicintlengthOfLongestSubstringKDistinct(String s,int k) {int left =0;int max =0;LinkedHashMap<Character,Integer> map =newLinkedHashMap<>();for (int i =0; i <s.length(); i++) {char c =s.charAt(i);if (map.containsKey(c)) {map.remove(c); }map.put(c, i);if(map.size() > k) { char key =map.keySet().iterator().next(); left =map.get(key) +1;map.remove(key); } max =Math.max(max, i - left +1); }return max; }}