lintcode 386. 最多有k个不同字符的最长子字符串
注意区分substring 和subsequence,即注意区分子串和子序列
给定字符串S,找到最多有k个不同字符的最长子串T。
样例
样例 1:
输入: S = “eceba” 并且 k = 3
输出: 4
解释: T = “eceb”
样例 2:
输入: S = “WORLD” 并且 k = 4
输出: 4
解释: T = “WORL” 或 “ORLD”
挑战
O(n) 时间复杂度
-
分析
这道题,需要先理解清子串和子序列的概念,自己经常,被他们弄乱,以至于,做题时,常常怀疑,题目到底说的啥,其实是自己的问题。
比如,“中出”是“我们中出了一个叛徒”的子串。注意子串和子序列是不同的:“苹机”是“苹果手机”的子序列,而不是子串。
前缀和后缀是两种特殊的子串:一个前缀在原串的开始位置出现,而一个后缀在原串的末端出现。
例如,“苹果手机”的所有子串是:“”(空串),“苹”,“果”,“手”,“机”,“苹果”,“果手”,“手机”,“苹果手”,“果手机”,“苹果手机”。
解题思路,就是用flag标记是否访问,以及访问了几次,并遍历,在到达k时更新记录。 -
code
class Solution {
public:
/**
* @param s: A string
* @param k: An integer
* @return: An integer
*/
int flag[256];
int lengthOfLongestSubstringKDistinct(string &s, int k) {
memset(flag,0,256*4);//memset是对char操作的
int max=0;int count=0;
int i=0;
for(int j=0;j<s.size();j++){
if(flag[s[j]]==0)count++;
flag[s[j]]++;
if(count>k){
flag[s[i]]--;
if(flag[s[i]]==0)count--;
i++;
}
if(max<(j-i+1))max=j-i+1;
}
return max;
}
};
- 垃圾代码时间
//这?
//其实,最终通过,还是改成了code1的逻辑,并且代码表示垃圾,以后一定先把逻辑理清,
//先在草纸上演算清楚,并想好代码逻辑,别一上来就写;
class Solution {
public:
/**
* @param s: A string
* @param k: An integer
* @return: An integer
*/
int flag[256];
int lengthOfLongestSubstringKDistinct(string &s, int k) {
memset(flag,0,256*4);//这个也注意,memset是对char的大小进行的
int max=0;int count=0;
if(k==0)return 0;
int j=0;
for(int i=0;i<s.size();i++){
//for(int j=i;j<s.size();j++){
//错误代码分析,j到达末尾后,会进入下一次循环,
//并重新计算flag,count,且原来的数据还在,故,结果偏大,ac失败
//主要是,还没考虑清楚,怎么解决,就开始写代码了,逻辑上还没清楚
//所以,写代码前,一定先在纸上,多推演几个例子,看看方法行不行
for(;j<s.size();j++){//之所以,把j提出来,是因为,下次循环,内层j重新计算,造成count/flag重复计算
if(flag[s[j]]==0)count++;
flag[s[j]]++;
if(count==k){
cout<<j-i+1<<endl;
if(max<(j-i+1)){
max=(j-i+1);
}
}else if(count>k){
flag[s[i]]--;
if(flag[s[i]]==0){
count--;
}
j++;//因为break,所以下次进入j,还是原来break后的值,所以需要提前+1,
break;//因为已经达到k的最大字串,所以可以停止后端,扩展了,
}
}
}
if(max<k)max=s.size();//这个是防止,整个串都达不到k的要求
return max;
}
};
/*
输入
"eqgkcwGFvjjmxutystqdfhuMblWbylgjxsxgnoh"
16
输出
31
期望答案
27
*/
- 错误代码分析
class Solution {
public:
/**
* @param s: A string
* @param k: An integer
* @return: An integer
*/
int flag[256];
int lengthOfLongestSubstringKDistinct(string &s, int k) {
memset(flag,0,256*4);//这个也注意,memset是对char的大小进行的
int max=0;int count=0;
if(k==0)return 0;
int j=0;
for(int i=0;i<s.size();i++){
for(int j=i;j<s.size();j++){
//错误代码分析,j到达末尾后,会进入下一次循环,
//并重新计算flag,count,且原来的数据还在,故,结果偏大,ac失败
//主要是,还没考虑清楚,怎么解决,就开始写代码了,逻辑上还没清楚
//所以,写代码前,一定先在纸上,多推演几个例子,看看方法行不行
if(flag[s[j]]==0){
flag[s[j]]=1;
count++;
}else{
flag[s[j]]++;
}
if(count==k){
if(max<(j-i+1)){
max=(j-i+1);
}
}else if(count>k){
flag[s[i]]--;
if(flag[s[i]]==0){
count--;
}
}
}
}
if(max<count){
//这分析的也不对,
//1.有可能count就没记上数,因为没达到k,所以应该和k比较,没到达k,则max=s.size()
//2. 比count没用,因为count的产生,就说明有k个了,则一定会记录max
//3. 像当时考虑,最后可能没到达k,但是count记录,所以max=count,但是你又错了,max使用j-i+1更新的,不是用count
max=count;
}
return max;
}
};
/*
输入
"eqgkcwGFvjjmxutystqdfhuMblWbylgjxsxgnoh"
16
输出
31
期望答案
27
*/