[LeetCode] 1156. Swap For Longest Repeated Character Substring 單字符重復子串的最大長度



Given a string text, we are allowed to swap two of the characters in the string. Find the length of the longest substring with repeated characters.

Example 1:

Input: text = "ababa"
Output: 3
Explanation: We can swap the first 'b' with the last 'a', or the last 'b' with the first 'a'. Then, the longest repeated character substring is "aaa", which its length is 3.

Example 2:

Input: text = "aaabaaa"
Output: 6
Explanation: Swap 'b' with the last 'a' (or the first 'a'), and we get longest repeated character substring "aaaaaa", which its length is 6.

Example 3:

Input: text = "aaabbaaa"
Output: 4

Example 4:

Input: text = "aaaaa"
Output: 5
Explanation: No need to swap, longest repeated character substring is "aaaaa", length is 5.

Example 5:

Input: text = "abcdef"
Output: 1

Constraints:

  • 1 <= text.length <= 20000
  • text consist of lowercase English characters only.

這道題給了一個字符串 text,說是可以交換任意位置的兩個字符一次,問可以得到的最長的重復字符子串的長度。所謂的重復字符的子串就是所有字符都相同的子串,題目中給的例子很好的說明了題意。本題的難點就在於可以交換任意位置的兩個字符一次,就好像是在斗地主的時候,總是在關鍵的位置缺少一張牌,沒法形成連牌,而此時假如 joker 可以代替任意一張牌的話,就可能組成連牌。這里交換字符操作也是為了盡可能的讓相同的字符靠在一起,如果不考慮代碼實現,給你一個字符串,如何找最長的重復子串,博主會數連續相同的字符,若此時有一個不同字符出現了,只要后面還有相同的字符,就會繼續數下去,因為有一次交換的機會,什么時候停止呢,當再次出現不同字符的時候就停止,或者是當前統計個數等於該字符出現的總個數時也停止,因為得到的結果不可能超過某個字符出現的總個數。所以可以先統計每個字符的出現次數,然后開始遍歷字符,對於每個遍歷到的字符,都開始數之后跟其相等的字符,新建變量j,cnt,和 diff,當j小於n,且當前字符和比較字符相同,或者 diff 等於0,且 cnt 小於比較字符出現的總個數時進行遍歷,若當前遍歷到的字符和要比較的字符不相等,說明該使用交換操作了,diff 自增1,此時將i更新為 j-1,這是一個優化操作,可以避免一些不必要的計算,下次從這個位置往后統計,也相當於重置了 diff。還有就是這個 cnt 小於字符出現總個數這個條件卡的非常好,即便下一個還是相同字符,也不能再統計了,因為最后的這個相同字符可能是要用來交換前面的斷點位置的。每次用統計出來的 cnt 更新結果 res,但是一個方向的遍歷可能無法應對所有情況,比如 "acbaaa",若只是從前往后遍歷,那么最終只能得到3,而正確的答案是4,因為可以將b和第一個a交換,所以還需要從后往前進行一次相同的操作,這樣才能得到正確的答案,參見代碼如下:


解法一:

class Solution {
public:
    int maxRepOpt1(string text) {
        int res = 0, n = text.size();
        unordered_map<char, int> charCnt;
        for (char c : text) ++charCnt[c];
        for (int i = 0; i < n; ++i) {
            char cur = text[i];
            int j = i, cnt = 0, diff = 0;
            while (j < n && (text[j] == cur || diff == 0) && cnt < charCnt[cur]) {
                if (cur != text[j]) {
                    ++diff;
                    i = j - 1;
                }
                ++cnt;
                ++j;
            }
            res = max(res, cnt);
        }
        for (int i = n - 1; i >= 0; --i) {
            char cur = text[i];
            int j = i, cnt = 0, diff = 0;
            while (j >= 0 && (text[j] == cur || diff == 0) && cnt < charCnt[cur]) {
                if (cur != text[j]) {
                    ++diff;
                    i = j + 1;
                }
                ++cnt;
                --j;
            }
            res = max(res, cnt);
        }
        return res;
    }
};

上面的解法嚴格來說還是平方級的,再來看一種線性時間的解法,可能比較難想,由於這里需要關注的是相同字符的出現位置,所以可以將所有相同的字符的位置都放到一個數組中,那么這里就建立一個字符和其出現位置數組之間的映射。由於題目中限制了只有英文字母,所以可以按照每個字母進行遍歷,直接遍歷每個字符的位置數組,這里新建變量 cnt,cnt2,和 mx,其中 cnt 統計的是連續字母的個數,cnt2 相當於一個臨時變量,當使用交換操作時,保存之前的 cnt 值,mx 為二者之和。在遍歷完某個字母位置數組之后,最后看一下若該字母出現總個數大於 mx,則說明交換后的字母還沒有統計進去,不管之前有沒有使用交換操作,都需要加上這個額外的一個,參見代碼如下:


解法二:

class Solution {
public:
    int maxRepOpt1(string text) {
        int res = 0, n = text.size();
        unordered_map<char, vector<int>> idxMap;
        for (int i = 0; i < n; ++i) idxMap[text[i]].push_back(i);
        for (char c = 'a'; c <= 'z'; ++c) {
            int cnt = 1, cnt2 = 0, mx = 0;
            for (int i = 1; i < idxMap[c].size(); ++i) {
                if (idxMap[c][i] == idxMap[c][i - 1] + 1) {
                    ++cnt;
                } else {
                    cnt2 = (idxMap[c][i] == idxMap[c][i - 1] + 2) ? cnt : 0;
                    cnt = 1;
                }
                mx = max(mx, cnt + cnt2);
            }
            res = max(res, mx + (idxMap[c].size() > mx ? 1 : 0));
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1156


參考資料:

https://leetcode.com/problems/swap-for-longest-repeated-character-substring/

https://leetcode.com/problems/swap-for-longest-repeated-character-substring/discuss/355922/C%2B%2B-2-approaches

https://leetcode.com/problems/swap-for-longest-repeated-character-substring/discuss/355866/Intuitive-Java-Solution-With-Explanation


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

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



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