• 395.至少有 K 个重复字符的最长子串


    题目

    给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于k 。返回这一子串的长度。

    示例 1:

    输入:s = "aaabb", k = 3
    输出:3
    解释:最长子串为 "aaa" ,其中 'a' 重复了 3 次。

    示例 2:

    输入:s = "ababbc", k = 2
    输出:5
    解释:最长子串为 "ababb" ,其中 'a' 重复了 2 次, 'b' 重复了 3 次

    暴力法+Mask

    暴力法的思路是遍历每一个子串,检测子串是否每个字符出现次数都不小于k,而检测需要遍历hashmap。在暴力法的基础上,我们使用mask实现O(1)时间检测子串是否每个字符出现次数都不小于k,从而降低时间复杂度。方法是定义一个int型的mask,int有32位,可用低26位对应每一个小写字母,数位为1表示该位对应字符出现次数没有达到k次,为0则表示出现次数大于等于k。这样只要mask==0即可说明对应子串每个字符出现次数都不小于k次。

      public int longestSubstring(String s, int k) {
            int i=0,n=s.length(),maxLen=0;
            //遍历每一个子串[i,j]
            while(i<=n-k){
                //记录子串[i,j]每个字符出现的次数
                int[] charCount=new int[26];
                int mask=0,idx=i;
                for(int j=i;j<n;++j){
                    int t=s.charAt(j)-'a';
                    charCount[t]++;
                    //mask第t位置为0
                    if(charCount[t]>=k) mask&=(~(1<<t));
                    //mask第t位置为1
                    else mask|=(1<<t);
                    if(mask==0&&j-i+1>maxLen){
                        maxLen=j-i+1; 
                        idx=j;
                    }
                }
                i=idx+1;
            }
            return maxLen;
      }
    

    滑动窗口法

    子串不同字符数的范围在1-26,枚举子串不同字符数,维护一个窗口保持每一次窗口内不同字符数不变。

     public int longestSubstring(String s, int k) {
            int maxLen=0,n=s.length();
            for(int cnt=1;cnt<=26;++cnt){
                //uniqueCnt记录窗口内不同字符数
                int left=0,right=0,uniqueCnt=0;
                //记录窗口内每个字符出现的次数
                int[] charCount=new int[26];
                while(right<n){
                    boolean valid=true;
                    //当窗口内不同字符数大于cnt时,窗口左指针不断右移,知道不同字符数等于cnt
                    //同时注意窗口左指针右移时charCount会有改变
                    while(uniqueCnt>cnt){
                        if(--charCount[s.charAt(left++)-'a']==0) uniqueCnt--;
                    }
                    if(charCount[s.charAt(right++)-'a']++==0) uniqueCnt++;
                    //对于每一个窗口,遍历charCount判断窗口内字符串是否每个字符出现次数都不小于k
                    for(int i=0;i<26;++i){
                        if(charCount[i]>0&&charCount[i]<k) {valid=false;break;}
                    }
                    if(valid&&maxLen<right-left) maxLen=right-left;
                }
            }
            return maxLen;
     }
    

    分治法

    为了寻找符合条件的子串,那么字符串s中出现次数小于k的字符则不能包含在内,因此这些不符合条件的字符就相当于是分隔符,将字符串切分成了好多了字串,而对于每个字串,我们想在其中寻找到最长的符合要求的子串,因此这就是求原问题的子问题,很明显可以用分治算法。当s所有字符出现次数都不小于k或s为空串时递归结束。

      public int longestSubstring(String s, int k) {
            int res=0,n=s.length();
            int[] charCount=new int[26];
            for(int i=0;i<n;++i) charCount[s.charAt(i)-'a']++;
            boolean valid=true; 
            for(int i=0;i<n;++i){
                if(charCount[s.charAt(i)-'a']<k){
                    valid=false;
                    int l1=longestSubstring(s.substring(0,i),k);
                    int l2=longestSubstring(s.substring(i+1),k);
                    res=Math.max(l1,l2);
                    break;
                }
            }
            //valid为true说明s每个字符出现次数都不小于k或s为空串,此时返回它的长度n即可
            return valid?n:res;
      }
    

    原题395.至少有 K 个重复字符的最长子串

  • 相关阅读:
    简单网络问题排查记录一
    安装mysql_sniffer报错undefined reference to symbol 'pthread_setspecific@@GLIBC_2.2.5'问题
    tengine安装ngx_http_lua_module
    Django——URL详解/Django中URL是如何与urls文件匹配的
    Python学习——enumerate
    Python学习——装饰器/decorator/语法糖
    缓存优化
    页面重绘 回流及其优化
    window.getComputedStyle()方法的使用及其扩展
    java 三个循环的优缺点
  • 原文地址:https://www.cnblogs.com/Frank-Hong/p/14660723.html
Copyright © 2020-2023  润新知