[LeetCode] Longest Substring with At Least K Repeating Characters 至少有K個重複字元的最長子字串
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.
Example 1:
Input: s = "aaabb", k = 3 Output: 3 The longest substring is "aaa", as 'a' is repeated 3 times.
Example 2:
Input: s = "ababbc", k = 2 Output: 5 The longest substring is "ababb", as 'a' is repeated 2 times and 'b' is repeated 3 times.
這道題給了我們一個字串s和一個正整數k,讓我們求一個最大子字串並且每個字元必須至少出現k次。作為LeetCode第三次程式設計比賽的壓軸題目,博主再一次沒有做出來,雖然難度標識只是Medium。後來在網上膜拜學習了大神們的解法,發現我當時的沒做出來的原因主要是卡在瞭如何快速的判斷某一個字串是否所有的元素都已經滿足了至少出現k次這個條件,雖然我也用雜湊表建立了字元和其出現次數之間的對映,但是如果每一次都要遍歷雜湊表中的所有字元看其出現次數是否大於k,未免有些不高效。而用mask就很好的解決了這個問題,由於字母只有26個,而整型mask有32位,足夠用了,每一位代表一個字母,如果為1,表示該字母不夠k次,如果為0就表示已經出現了k次,這種思路真是太聰明瞭,隱約記得這種用法在之前的題目中也用過,但是博主並不能舉一反三(沮喪臉:(),還得繼續努力啊。我們遍歷字串,對於每一個字元,我們都將其視為起點,然後遍歷到末尾,我們增加雜湊表中字母的出現次數,如果其小於k,我們將mask的對應位改為1,如果大於等於k,將mask對應位改為0。然後看mask是否為0,是的話就更新res結果,然後把當前滿足要求的子字串的起始位置j儲存到max_idx中,等內層迴圈結束後,將外層迴圈變數i賦值為max_idx+1,繼續迴圈直至結束,參見程式碼如下:
解法一:
class Solution { public: int longestSubstring(string s, int k) { int res = 0, i = 0, n = s.size(); while (i + k <= n) { int m[26] = {0}, mask = 0, max_idx = i; for (int j = i; j < n; ++j) { int t = s[j] - 'a';++m[t]; if (m[t] < k) mask |= (1 << t); else mask &= (~(1 << t)); if (mask == 0) { res = max(res, j - i + 1); max_idx = j; } } i = max_idx + 1; } return res; } };
下面這種寫法是上面的解法的遞迴寫法,看起來簡潔了不少,但是個人感覺比較難想,參見程式碼如下:
解法二:
class Solution { public: int longestSubstring(string s, int k) { int n = s.size(), max_idx = 0, res = 0; int m[128] = {0}; bool ok = true; for (char c : s) ++m[c]; for (int i = 0; i < n; ++i) { if (m[s[i]] < k) { res = max(res, longestSubstring(s.substr(max_idx, i - max_idx), k)); ok = false; max_idx = i + 1; } } return ok ? n : max(res, longestSubstring(s.substr(max_idx, n - max_idx), k)); } };
類似題目:
參考資料: