386. 最多有k个不同字符的最长子字符串

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
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值