[LeetCode] 340. Longest Substring with At Most K Distinct Characters

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

Example 1:

Input: s = "eceba", k = 2
Output: 3
Explanation: T is "ece" which its length is 3.

Example 2:

Input: s = "aa", k = 1
Output: 2
Explanation: T is "aa" which its length is 2.

Solution 1. Brute force, O(N^3) runtime

For each possible substring, check if it contains at most k distinct characters, then get the longest.

 1 class Solution {
 2     public int lengthOfLongestSubstringKDistinct(String s, int k) {
 3         int max = 0;
 4         for(int i = 0; i < s.length(); i++) {
 5             for(int j = i + 1; j <= s.length(); j++) {
 6                 String sub = s.substring(i, j);
 7                 Set<Character> chars = new HashSet<>();
 8                 for(int t = i; t < j; t++) {
 9                     chars.add(s.charAt(t));
10                 }
11                 if(chars.size() <= k) {
12                     max = Math.max(max, sub.length());
13                 }
14             }
15         }
16         return max;
17 }

Solution 2. O(N^2) runtime

One thing that can be optimized in solution 1 is to use checked substring‘s characters counts to determine if the next substring of the same length satisfies the condition, from O(N) to O(1). This is done by maintaining a hashmap of each distinct character‘s frequency.

1. Initialize a hash map of each distinct character‘s frequency.

2. Starting from the possible maximum length n = s.length(), do the following.

  a. from left to right, slide a window of length n to check if a substring meets the required condition. If it does, return; otherwise keep sliding one character at a time until reaching the right end.

  b. reduce sliding window length by 1 and from right to left, slide a window of length n to check if a substring meets the required condition. If it does, return; otherwise keep sliding one character at a time until reaching the left end.

  c. repeat a and b until n = 0.

 1 class Solution {
 2     public int lengthOfLongestSubstringKDistinct(String s, int k) {
 3         int[] counts = new int[256];
 4         for(int i = 0; i < s.length(); i++) {
 5             counts[s.charAt(i) - ‘\0‘]++;
 6         }
 7         int uniqueChars = 0;
 8         for(int i = 0; i < 256; i++) {
 9             if(counts[i] > 0) {
10                 uniqueChars++;
11             }
12         }
13         int maxLen = s.length();
14         boolean leftToRight = false;
15
16         for(; maxLen > 0; maxLen--) {
17             leftToRight = !leftToRight;
18             if(leftToRight) {
19                 int leftIdx = 0, rightIdx = maxLen - 1;
20                 if(rightIdx + 1 < s.length()) {
21                     counts[s.charAt(rightIdx + 1) - ‘\0‘]--;
22                     if(counts[s.charAt(rightIdx + 1) - ‘\0‘] == 0) {
23                        uniqueChars--;
24                     }
25                 }
26                 if(uniqueChars <= k) {
27                     return maxLen;
28                 }
29                 rightIdx ++;
30                 while(rightIdx < s.length()) {
31                     counts[s.charAt(leftIdx) - ‘\0‘]--;
32                     if(counts[s.charAt(leftIdx) - ‘\0‘] == 0) {
33                         uniqueChars--;
34                     }
35                     leftIdx++;
36
37                     if(counts[s.charAt(rightIdx) - ‘\0‘] == 0) {
38                         uniqueChars++;
39                     }
40
41                     counts[s.charAt(rightIdx) - ‘\0‘]++;
42                     if(uniqueChars <= k) {
43                         return maxLen;
44                     }
45                     rightIdx++;
46                 }
47             }
48             else {
49                 int rightIdx = s.length() - 1, leftIdx = s.length() - maxLen;
50                 if(leftIdx >= 1) {
51                     counts[s.charAt(leftIdx - 1) - ‘\0‘]--;
52                     if(counts[s.charAt(leftIdx - 1) - ‘\0‘] == 0) {
53                        uniqueChars--;
54                     }
55                 }
56                 if(uniqueChars <= k) {
57                     return maxLen;
58                 }
59                 leftIdx--;
60                 while(leftIdx >= 0) {
61                     counts[s.charAt(rightIdx) - ‘\0‘]--;
62                     if(counts[s.charAt(rightIdx) - ‘\0‘] == 0) {
63                         uniqueChars--;
64                     }
65                     rightIdx--;
66
67                     if(counts[s.charAt(leftIdx) - ‘\0‘] == 0) {
68                         uniqueChars++;
69                     }
70                     counts[s.charAt(leftIdx) - ‘\0‘]++;
71                     if(uniqueChars <= k) {
72                         return maxLen;
73                     }
74                     leftIdx--;
75                 }
76             }
77         }
78         return maxLen;
79 }

Solution 3. O(N) runtime

To further optimize solution 2, we have the this observation: for a substring that starts at index i, s[i, j - 1], if it meets the condition while s[i, j] does not, we do not need to backtrack j to i + 1.This is true because all the substring from index i + 1 to j - 1 are a smaller set of s[i, j - 1]. If s[i, j - 1] is a possible solution, it eliminates the need of checking a smaller solution. We just need to increment i by 1 and pick up where j stopped.

For substrings that start at index i, there are two cases when we will stop incrementing j.

1. s[i, j] has more than k distinct characters; In this case, we need to update the frequency of s.charAt(i), increment i by 1 then repeat the same process.

2. j is out of bound, j == s.length();  In this case, we‘ve found the answer as no other qualified substrings will have a longer length(i can only be incremented).

The runtime is O(N) as both the start index i and end index j only move forward, which means at any given iteration, either i or j is incremented. This takes linear time to finish.

 1 class Solution {
 2     public int lengthOfLongestSubstringKDistinct(String s, int k) {
 3         if(s == null || s.length() == 0 || k <= 0){
 4             return 0;
 5         }
 6         int[] counts = new int[256];
 7         int distinctChars = 0;
 8         int endIdx = 0, maxLen = 0;
 9         for(int startIdx = 0; startIdx < s.length(); startIdx++) {
10             while(endIdx < s.length()) {
11                 if(counts[s.charAt(endIdx) - ‘\0‘] > 0) {
12                     counts[s.charAt(endIdx) - ‘\0‘]++;
13                 }
14                 else if(distinctChars == k){
15                     break;
16                 }
17                 else {
18                     counts[s.charAt(endIdx) - ‘\0‘]++;
19                     distinctChars++;
20                 }
21                 endIdx++;
22             }
23             maxLen = Math.max(maxLen, endIdx - startIdx);
24             if(endIdx == s.length()) {
25                 break;
26             }
27             counts[s.charAt(startIdx) - ‘\0‘]--;
28             if(counts[s.charAt(startIdx) - ‘\0‘] == 0) {
29                 distinctChars--;
30             }
31         }
32         return maxLen;
33     }
34 }


原文地址:https://www.cnblogs.com/lz87/p/10095363.html

时间: 2024-07-31 09:27:13

[LeetCode] 340. Longest Substring with At Most K Distinct Characters的相关文章

[LeetCode] 340. Longest Substring with At Most K Distinct Characters 最多有K个不同字符的最长子串

Given a string, find the length of the longest substring T that contains at most k distinct characters. For example, Given s = “eceba” and k = 2, T is "ece" which its length is 3. 159. Longest Substring with At Most Two Distinct Characters 的拓展,1

340. Longest Substring with At Most K Distinct Characters

/* * 340. Longest Substring with At Most K Distinct Characters * 2016-7-10 by Mingyang * 利用HashMap来做sliding window的做法非常好! */ public int lengthOfLongestSubstringKDistinct(String s, int k) { Map<Character, Integer> map = new HashMap<>(); int lef

[LeetCode] Longest Substring with At Most K Distinct Characters 最多有K个不同字符的最长子串

Given a string, find the length of the longest substring T that contains at most k distinct characters. For example, Given s = “eceba” and k = 2, T is "ece" which its length is 3. 这道题是之前那道Longest Substring with At Most Two Distinct Characters的拓展

LeetCode &quot;Longest Substring with At Most K Distinct Characters&quot;

A simple variation to "Longest Substring with At Most Two Distinct Characters". A typical sliding window problem. class Solution { public: int lengthOfLongestSubstringKDistinct(string s, int k) { unordered_map<char, unsigned> hm; int ret =

【LeetCode】Longest Substring with At Most Two Distinct Characters (2 solutions)

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. 这个题很显然使用双指针进行遍历的,beg

Longest Substring with At Most K Distinct Characters

Given a string, find the longest substring that contains only two unique characters. For example, given "abcbbbbcccbdddadacb", the longest substring that contains k unique character is "bcbbbbcccb". 分析: 用hashmap记录每个character从start到当前位置

LeetCode 395. Longest Substring with At Least K Repeating Characters

原题链接在这里:https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/ 题目: Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k 

LeetCode 395. Longest Substring with At Least K Repeating Characters C#

Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times. Example 1: Input: s = "aaabb", k = 3 Output: 3 The longest substring is "aaa"

leetcode 159. Longest Substring with At Most Two Distinct Characters 求两个字母组成的最大子串长度 --------- java

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. 给一个字符串,求这个字符串中,由两个字母组成的,连续的最长子串的长度. 虽然是hard,但是感觉并没有什么难度. 用ch1和pre