给定一个字符串S和一个数字K 。任务是找到恰好具有 K 个不同字符的最小长度子串。
注意:字符串S 仅由小写英文字母组成。
例子:
Input: S = "ababcb", K = 3
Output: abc
Input: S="efecfefd", K = 4
Output: cfefd
简单的解决方案:简单的解决方案是考虑每个子字符串并检查它是否包含 k 个不同的字符。如果是,则将此子字符串的长度与之前找到的最小长度子字符串进行比较。这种方法的时间复杂度是 O(N 2 ),其中 N 是字符串 S 的长度。
有效的解决方案:一个有效的解决方案是使用滑动窗口技术和散列。这个想法是使用两个指针st和end来表示滑动窗口的起点和终点。最初将两者都指向字符串的开头。向前移动 end 并增加相应字符的计数。如果计数为 1,则找到一个新的不同字符并增加不同字符数的计数。如果不同字符数的计数大于k则向前移动st并减少字符的计数。如果字符计数为零,则删除一个不同的字符,并且可以通过这种方式将不同元素的计数减少到k 。如果不同元素的计数为k ,则通过向前移动 st 从滑动窗口的开头删除计数大于 1 的字符。将当前滑动窗口的长度与迄今为止找到的最小长度进行比较,并在必要时进行更新。
请注意,每个字符最多只能从滑动窗口中添加和删除一次,因此每个字符被遍历两次。因此时间复杂度是线性的。
下面是上述方法的实现:
C++
// C++ program to find minimum length substring
// having exactly k distinct character.
#include
using namespace std;
// Function to find minimum length substring
// having exactly k distinct character.
string findMinLenStr(string str, int k)
{
int n = str.length();
// Starting index of sliding window.
int st = 0;
// Ending index of sliding window.
int end = 0;
// To store count of character.
int cnt[26];
memset(cnt, 0, sizeof(cnt));
// To store count of distinct
// character in current sliding
// window.
int distEle = 0;
// To store length of current
// sliding window.
int currlen;
// To store minimum length.
int minlen = n;
// To store starting index of minimum
// length substring.
int startInd = -1;
while (end < n) {
// Increment count of current character
// If this count is one then a new
// distinct character is found in
// sliding window.
cnt[str[end] - 'a']++;
if (cnt[str[end] - 'a'] == 1)
distEle++;
// If number of distinct characters is
// is greater than k, then move starting
// point of sliding window forward,
// until count is k.
if (distEle > k) {
while (st < end && distEle > k) {
if (cnt[str[st] - 'a'] == 1)
distEle--;
cnt[str[st] - 'a']--;
st++;
}
}
// Remove characters from the beginning of
// sliding window having count more than 1
// to minimize length.
if (distEle == k) {
while (st < end && cnt[str[st] - 'a'] > 1) {
cnt[str[st] - 'a']--;
st++;
}
// Compare length with minimum length
// and update if required.
currlen = end - st + 1;
if (currlen < minlen) {
minlen = currlen;
startInd = st;
}
}
end++;
}
// Return minimum length substring.
return str.substr(startInd, minlen);
}
// Driver code
int main()
{
string str = "efecfefd";
int k = 4;
cout << findMinLenStr(str, k);
return 0;
}
Java
// Java program to find minimum length subString
// having exactly k distinct character.
class GFG
{
// Function to find minimum length subString
// having exactly k distinct character.
static String findMinLenStr(String str, int k)
{
int n = str.length();
// Starting index of sliding window.
int st = 0;
// Ending index of sliding window.
int end = 0;
// To store count of character.
int cnt[] = new int[26];
for(int i = 0; i < 26; i++)cnt[i] = 0;
// To store count of distinct
// character in current sliding
// window.
int distEle = 0;
// To store length of current
// sliding window.
int currlen;
// To store minimum length.
int minlen = n;
// To store starting index of minimum
// length subString.
int startInd = -1;
while (end < n)
{
// Increment count of current character
// If this count is one then a new
// distinct character is found in
// sliding window.
cnt[str.charAt(end) - 'a']++;
if (cnt[str.charAt(end) - 'a'] == 1)
distEle++;
// If number of distinct characters is
// is greater than k, then move starting
// point of sliding window forward,
// until count is k.
if (distEle > k)
{
while (st < end && distEle > k)
{
if (cnt[str.charAt(st) - 'a'] == 1)
distEle--;
cnt[str.charAt(st) - 'a']--;
st++;
}
}
// Remove characters from the beginning of
// sliding window having count more than 1
// to minimize length.
if (distEle == k)
{
while (st < end && cnt[str.charAt(st) - 'a'] > 1)
{
cnt[str.charAt(st) - 'a']--;
st++;
}
// Compare length with minimum length
// and update if required.
currlen = end - st + 1;
if (currlen < minlen)
{
minlen = currlen;
startInd = st;
}
}
end++;
}
// Return minimum length subString.
return str.substring(startInd,startInd + minlen);
}
// Driver code
public static void main(String args[])
{
String str = "efecfefd";
int k = 4;
System.out.println(findMinLenStr(str, k));
}
}
// This code is contributed by Arnab Kundu
Python 3
# Python 3 program to find minimum length
# substring having exactly k distinct character.
# Function to find minimum length substring
# having exactly k distinct character.
def findMinLenStr(str, k):
n = len(str)
# Starting index of sliding window.
st = 0
# Ending index of sliding window.
end = 0
# To store count of character.
cnt = [0] * 26
# To store count of distinct
# character in current sliding
# window.
distEle = 0
# To store length of current
# sliding window.
currlen =0
# To store minimum length.
minlen = n
# To store starting index of minimum
# length substring.
startInd = -1
while (end < n):
# Increment count of current character
# If this count is one then a new
# distinct character is found in
# sliding window.
cnt[ord(str[end]) - ord('a')] += 1
if (cnt[ord(str[end]) - ord('a')] == 1):
distEle += 1
# If number of distinct characters is
# is greater than k, then move starting
# point of sliding window forward,
# until count is k.
if (distEle > k):
while (st < end and distEle > k):
if (cnt[ord(str[st]) -
ord('a')] == 1):
distEle -= 1
cnt[ord(str[st]) - ord('a')] -= 1
st += 1
# Remove characters from the beginning of
# sliding window having count more than 1
# to minimize length.
if (distEle == k):
while (st < end and cnt[ord(str[st]) -
ord('a')] > 1):
cnt[ord(str[st]) - ord('a')] -= 1
st += 1
# Compare length with minimum length
# and update if required.
currlen = end - st + 1
if (currlen < minlen):
minlen = currlen
startInd = st
end += 1
# Return minimum length substring.
return str[startInd : startInd + minlen]
# Driver code
if __name__ == "__main__":
str = "efecfefd"
k = 4
print(findMinLenStr(str, k))
# This code is contributed by Ita_c
C#
// C# program to find minimum length subString
// having exactly k distinct character.
using System;
class GFG
{
// Function to find minimum length subString
// having exactly k distinct character.
static String findMinLenStr(string str, int k)
{
int n = str.Length;
// Starting index of sliding window.
int st = 0;
// Ending index of sliding window.
int end = 0;
// To store count of character.
int []cnt = new int[26];
for(int i = 0; i < 26; i++)cnt[i] = 0;
// To store count of distinct
// character in current sliding
// window.
int distEle = 0;
// To store length of current
// sliding window.
int currlen;
// To store minimum length.
int minlen = n;
// To store starting index of minimum
// length subString.
int startInd = -1;
while (end < n)
{
// Increment count of current character
// If this count is one then a new
// distinct character is found in
// sliding window.
cnt[str[end] - 'a']++;
if (cnt[str[end] - 'a'] == 1)
distEle++;
// If number of distinct characters is
// is greater than k, then move starting
// point of sliding window forward,
// until count is k.
if (distEle > k)
{
while (st < end && distEle > k)
{
if (cnt[str[st] - 'a'] == 1)
distEle--;
cnt[str[st] - 'a']--;
st++;
}
}
// Remove characters from the beginning of
// sliding window having count more than 1
// to minimize length.
if (distEle == k)
{
while (st < end && cnt[str[st] - 'a'] > 1)
{
cnt[str[st] - 'a']--;
st++;
}
// Compare length with minimum length
// and update if required.
currlen = end - st + 1;
if (currlen < minlen)
{
minlen = currlen;
startInd = st;
}
}
end++;
}
// Return minimum length subString.
return str.Substring(startInd, minlen);
}
// Driver code
public static void Main()
{
string str = "efecfefd";
int k = 4;
Console.WriteLine(findMinLenStr(str, k));
}
}
// This code is contributed by Ryuga
Javascript
输出:
cfefd
时间复杂度: O(N),其中 N 是给定字符串的长度。
辅助空间: O(1)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。