[Leetcode学习-java]少なくともK個の繰り返し文字を含む最長の部分文字列

問題:

難易度:中

説明:

文字列、数値K、および文字内の文字を任意の順序で指定すると、すべての文字の最も長い文字の長さが繰り返しになります> = K部分文字列(連続シーケンス)が返されます。

件名リンク:https//leetcode.com/problems/longest-substring-with-at-least-k-repeating-characters/

入力範囲:

 

  • 1 <= s.length <= 104
  • s 小文字の英字のみで構成されます。
  • 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.文字列全体の単語頻度を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