【字符串】B048_LC_至少有K個重複字符的最長子串(滑窗 + 分治 / 優化)

一、Problem

Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.

Input:
s = "aaabb", k = 3

Output:
3

The longest substring is "aaa", as 'a' is repeated 3 times.

二、Solution

方法一:滑動窗口

  • 窗口的含義
    • 囊括所有頻次 >= k 的字符
  • 窗口右移時機
    • 每次都右移
  • 窗口左移時機
    • 當窗口出現頻次 < k 的字符
  • 結算時機
    • 當遇到頻次 < k 的字符 s[i],則遞歸求解 ii 左側字符串的合法序列長度和 ii 右側字符串的合法序列長度
class Solution {
    int div(char[] s, int l, int r, int k) {
        int[] freq = new int[258];
        for (int i = l; i < r; i++) freq[s[i]]++;
        
        for (int i = l; i < r; i++) {
            if (freq[s[i]] < k) {
                int len1 = div(s, l, i, k);
                int len2 = div(s, i+1, r, k);
                return Math.max(len1, len2);
            }
        }
        return r-l;
    }
    public int longestSubstring(String s, int k) {
        return div(s.toCharArray(), 0, s.length(), k);
    }
}

複雜度分析

  • 時間複雜度:O(...)O(...)
  • 空間複雜度:O(...)O(...)

方法二:分治優化

優化:如果 ii 位置存在是一段長度爲 len 的都是不合法的子串,那麼在方法一中一定會在那裏調用 len 次 div 方法,這是不必要的。所以基於這個問題,我們可以想方法優化。在 ii 的左邊出現同樣情況也同理。

class Solution {
    int div(char[] s, int l, int r, int k) {
        int[] freq = new int[258];
        for (int i = l; i <= r; i++) freq[s[i]]++;

        while (l < r && freq[s[l]] < k)  l++;
        while (l < r && freq[s[r]] < k)  r--;
        
        for (int i = l; i <= r; i++) {
            if (freq[s[i]] < k) {
                int l1 = div(s, l, i-1, k);
                int l2 = div(s, i+1, r, k);
                return Math.max(l1, l2);
            }
        }
        return r-l+1;
    }
    public int longestSubstring(String s, int k) {
        return div(s.toCharArray(), 0, s.length()-1, k);
    }
}

複雜度分析

  • 時間複雜度:O(n)O(n)
  • 空間複雜度:O(1)O(1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章