[Leetcode学习-java]Longest Substring with At Least K Repeating Characters

问题:

难度:medium

说明:

给出一个字符串,一个数字 K,然后将字符串里面 字符任意顺序、长度最长 所有字符重复次数都 >= K 的 子串(连续子序列)返回。

题目连接:https://leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/

输入范围:

  • 1 <= s.length <= 104
  • s consists of only lowercase English letters.
  • 1 <= k <= 105

输入案例:

Example 1:
Input: s = "aaabb", k = 3
Output: 3
Explanation: The longest substring is "aaa", as 'a' is repeated 3 times.

Example 2:
Input: s = "ababbc", k = 2
Output: 5
Explanation: The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.

我的代码:

思考了很久,这个也 类似于 分治法的一种处理,但是并没有更好,更方便的思路,只好按照比较系统性的写法处理,所以第一版特别长,优化之后应该会断点。

1、算一次整个串的词频

2、然后把词频低于 k 的字符词频置 0 

3、因为进行了词频置 0 ,所以出现了 0 词频划分的区间,再对每个区间进行词频重算,继续 2 步骤

4、最后是统计每个区间长度即可

class Solution {
        public int longestSubstring(String s, int k) {
            if(k < 2) return s.length();
            int len = s.length(), total = 0, temp = 0;
            int[] fre = new int[len];
            int[] totals = new int[26];
            char[] chs = s.toCharArray();
            for(char ch : chs) // 先算一次词频
                totals[ch - 'a'] ++;

            for(int i = 0;i < len;i ++) // 对整个串都赋值上词频
                fre[i] = totals[chs[i] - 'a'];

            boolean zeroF = false;
            while(true) {

                for(int i = 0;i < len;i ++)
                    if(fre[i] != 0 && fre[i] < k) { // 将低于 k 除 0 外的词频置为0
                        zeroF = true;
                        fre[i] = 0;
                    }

                if(!zeroF) break;

                for(int i = 0;i < len;i ++) { // 把每个 0 对应的区间都进行重复计算
                    if(fre[i] == 0) {
                        reclculate(i + 1, len, fre, chs);
                    } else if(i == 0) recalculate(0, len, fre, chs);
                }


                zeroF = false;
            }

            for(int i = 0;i < len;i ++) { // 最后获得最长的区间长度
                if(fre[i] == 0) {
                    total = Math.max(temp, total);
                    temp = 0;
                } else
                    temp ++;
            }
            return Math.max(temp, total);
        }

        // 重新计算每个区间的重复次数
        private void recalculate(int i, int len, int[] fre, char[] chs) {
            if(i < len && fre[i] != 0) {
                int[] totals = new int[26];
                for(int j = i;j < len;j ++) {
                    if(fre[j] == 0) {
                        len = j;
                        break;
                    }
                    totals[chs[j] - 'a'] ++;
                }
                for(int j = i;j < len;j ++) {
                    fre[j] = totals[chs[j] - 'a'];
                }
            }
        }
}

猜你喜欢

转载自blog.csdn.net/qq_28033719/article/details/110227709