Skip to content

395. Longest Substring with At Least K Repeating Characters 👍

  • Time: $O(26n) = O(n)$
  • Space: $O(26) = O(1)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution {
 public:
  int longestSubstring(string s, int k) {
    int ans = 0;
    for (int n = 1; n <= 26; ++n)
      ans = max(ans, longestSubstringWithNUniqueLetters(s, k, n));
    return ans;
  }

 private:
  int longestSubstringWithNUniqueLetters(const string& s, int k, int n) {
    int res = 0;
    int uniqueLetters = 0;       // the number of unique letters
    int lettersHavingKFreq = 0;  // the number of letters having frequency >= k
    vector<int> count(26);

    for (int l = 0, r = 0; r < s.length(); ++r) {
      if (++count[s[r] - 'a'] == 1)
        ++uniqueLetters;
      if (count[s[r] - 'a'] == k)
        ++lettersHavingKFreq;
      while (uniqueLetters > n) {
        if (count[s[l] - 'a'] == k)
          --lettersHavingKFreq;
        if (--count[s[l] - 'a'] == 0)
          --uniqueLetters;
        ++l;
      }
      // Since both the number of unique letters and the number of letters
      // having frequency >= k are equal to n, this is a valid window.
      if (lettersHavingKFreq == n)  // Implicit: uniqueLetters == n
        res = max(res, r - l + 1);
    }

    return res;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
  public int longestSubstring(String s, int k) {
    int ans = 0;
    for (int n = 1; n <= 26; ++n)
      ans = Math.max(ans, longestSubstringWithNUniqueLetters(s, k, n));
    return ans;
  }

  private int longestSubstringWithNUniqueLetters(final String s, int k, int n) {
    int res = 0;
    int uniqueLetters = 0;      // the number of unique letters
    int lettersHavingKFreq = 0; // the number of letters having frequency >= k
    int[] count = new int[26];

    for (int l = 0, r = 0; r < s.length(); ++r) {
      if (++count[s.charAt(r) - 'a'] == 1)
        ++uniqueLetters;
      if (count[s.charAt(r) - 'a'] == k)
        ++lettersHavingKFreq;
      while (uniqueLetters > n) {
        if (count[s.charAt(l) - 'a'] == k)
          --lettersHavingKFreq;
        if (--count[s.charAt(l) - 'a'] == 0)
          --uniqueLetters;
        ++l;
      }
      // Since both the number of unique letters and the number of letters
      // having frequency >= k are equal to n, this is a valid window.
      if (lettersHavingKFreq == n) // Implicit: uniqueLetters == n
        res = Math.max(res, r - l + 1);
    }

    return res;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution:
  def longestSubstring(self, s: str, k: int) -> int:
    def longestSubstringWithNUniqueLetters(n: int) -> int:
      res = 0
      uniqueLetters = 0  # the number of unique letters
      lettersHavingKFreq = 0  # the number of letters having frequency >= k
      count = collections.Counter()

      l = 0
      for r, c in enumerate(s):
        count[c] += 1
        if count[c] == 1:
          uniqueLetters += 1
        if count[c] == k:
          lettersHavingKFreq += 1
        while uniqueLetters > n:
          if count[s[l]] == k:
            lettersHavingKFreq -= 1
          count[s[l]] -= 1
          if count[s[l]] == 0:
            uniqueLetters -= 1
          l += 1
        # Since both the number of unique letters and the number of letters
        # having frequency >= k are equal to n, this is a valid window.
        if lettersHavingKFreq == n:  # Implicit: uniqueLetters == n
          res = max(res, r - l + 1)

      return res

    return max(longestSubstringWithNUniqueLetters(n)
               for n in range(1, 27))