Description
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", as 'a' is repeated 3 times.
Example 2:
Input:
s = "ababbc", k = 2
Output:
5
The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
Solution
Divide and Conquer
考虑使用分治法,如果能找到一个字母在整个字符串中出现的次数小于k
次,那么这个字母一定不在结果中的子字符串中。
以这个字符的位置为分界点,把整个字符串分成左边left
和右边right
中。
同样的方法在left
和right
字符串中执行,最终结果为两者返回值中的最大值。
首先遍历数组,记录每一个字母出现的次数。
base case: 当所有的字符出现次数均大于k
次,返回这个字符串的长度
divide: 找到出现次数小于k
次的字符,以该字符为分解,把字符串分为左右两个子字符串。
conquer: 分治两个子字符串
combine: 返回左右子字符串返回结果的最大值
class Solution {
public int longestSubstring(String s, int k) {
return longestSubstring(s, k, 0, s.length()-1);
}
private int longestSubstring(String s, int k, int lo, int hi) {
// count the appearences of each character
int[] count = new int[26];
Arrays.fill(count, 0);
for (int i = lo; i <= hi; i++) count[s.charAt(i) - 'a']++;
// base case, when all characters appeares more than k times, return the length
int j;
for (j = lo; j <= hi; j++) {
if (count[s.charAt(j)-'a'] < k) break;
}
if (j > hi) return (hi - lo + 1); // when all character appeare more than k times.
// divide and conquer
int left = longestSubstring(s, k, lo, j-1);
int right = longestSubstring(s, k, j+1, hi);
// combine
return Math.max(left, right);
}
}
Sliding Window
import collections
class Solution(object):
"""算法思路:
快慢指针-Sliding Window
首先slow指针一直右移直到当前char的数量不小于k,然后fast指针从slow指针开始
往后遍历,一直到char的数量小于k,中间我们记录slow到fast之间是否所有的char
的数量都不小于k,并且记录满足上句条件时fast的位置index,然后把slow挪到index
上,如此循环,一直到slow指针等于s的长度。
什么时候用sliding window? 一般使用sliding window的情景都会满足以下条件:
- 当window满足条件时,fast再往前探不会有更优的结果
"""
def longestSubstring(self, s, k):
low, r, n, total = 0, 0, len(s), collections.Counter(s)
while low < n:
while low < n and total[s[low]] < k:
total[s[low]] -= 1
low += 1
if low >= n:
break
high, counter, mask, index = low, collections.defaultdict(
int), 0, low
while high < n and total[s[high]] >= k:
counter[s[high]] += 1
bit = 1 << ord(s[high]) - 97
if counter[s[high]] < k:
mask |= bit
else:
mask &= ~bit
if not mask:
index = high
r = max(r, high - low + 1)
high += 1
while low <= index:
total[low] -= 1
low += 1
return r
s = Solution()
print s.longestSubstring("ababbc", 2)