圖解leetcode —— 395. 至少有K個重復字符的最長子串


前言:

每道題附帶動態示意圖,提供java、python兩種語言答案,力求提供leetcode最優解。

描述:

找到給定字符串(由小寫字符組成)中的最長子串 T , 要求 T 中的每一字符出現次數都不少於 k 。輸出 T 的長度。

示例 1:

輸入:
s = "aaabb", k = 3

輸出:
3

最長子串為 "aaa" ,其中 'a' 重復了 3 次。


示例 2:

輸入:
s = "ababbc", k = 2

輸出:
5

最長子串為 "ababb" ,其中 'a' 重復了 2 次, 'b' 重復了 3 次。

思路:

這道題可以用滑動窗口+分治的方法進行解答。

java:

class Solution {

    /**
     * 計算最長重復子串長度.
     *
     * @param s 字符串
     * @param k 重復次數
     * @return 長度
     */
    public int longestSubstring(String s, int k) {
        int len = s.length();
        if (len == 0 || k > len) {
            return 0;
        }
        if (k < 2) {
            return len;
        }
        return countHandler(s.toCharArray(), k, 0, len - 1);
    }

    /**
     * 計算最長重復子串長度邏輯處理
     *
     * @param chars 字符數組
     * @param k     重復次數
     * @param start 開始位置
     * @param end   結束位置
     * @return 長度
     */
    private int countHandler(char[] chars, int k, int start, int end) {
        if (k > end - start + 1) {
            return 0;
        }
        // 計數器,26代表個字母
        int[] times = new int[26];
        // 統計字符頻率
        for (int i = start; i <= end; i++) {
            ++times[chars[i] - 'a'];
        }
        // 起點、終點夾逼,去掉首位不符合條件的字符串(滑動窗口)
        while (k <= end - start + 1 && times[chars[start] - 'a'] < k) {
            start++;
        }
        while (k <= end - start + 1 && times[chars[end] - 'a'] < k) {
            end--;
        }
        if (k > end - start + 1) {
            return 0;
        }
        // 字符串中間存在不符合條件的字符,即以該字符串為界,分割前子串和后字串,進行計算(分治)
        for (int i = start; i <= end; i++) {
            if (times[chars[i] - 'a'] < k) {
                return (Math.max(countHandler(chars, k, start, i - 1), countHandler(chars, k, i + 1, end)));
            }
        }
        return end - start + 1;
    }
}

結果:

python3:

class Solution:
    def longestSubstring(self, s: str, k: int) -> int:
        length = len(s)
        if length == 0 or k > length:
            return 0
        if k < 2:
            return length

        def countHandler(s: str, k: int, start: int, end: int) -> int:
            if k > end - start + 1:
                return 0
            # 初始化數組
            times = [0 for i in range(0, 27)]
            for i in range(start, end + 1):
                times[ord(s[i]) - ord('a')] += 1
            # 起點、終點夾逼,去掉首位不符合條件的字符串(滑動窗口)
            while end - start + 1 >= k > times[ord(s[start]) - ord('a')]:
                start += 1
            while end - start + 1 >= k > times[ord(s[end]) - ord('a')]:
                end -= 1
            if k > end - start + 1:
                return 0
            # 字符串中間存在不符合條件的字符,即以該字符串為界,分割前子串和后字串,進行計算(分治)
            for i in range(start, end):
                if times[ord(s[i]) - ord('a')] < k:
                    return max(countHandler(s, k, start, i - 1), countHandler(s, k, i + 1, end))
            return end - start + 1

        return countHandler(s, k, 0, length - 1)

結果:

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM