Problem
You are given a string s
consisting of the characters 'a'
, 'b'
, and 'c'
and a non-negative integer k
. Each minute, you may take either the leftmost character of s
, or the rightmost character of s
.
Return the minimum number of minutes needed for you to take at least k
of each character, or return -1
if it is not possible to take k
of each character.
Examples
Example 1:
Input: s = "aabaaaacaabc", k = 2
Output: 8
Explanation:
Take three characters from the left of s. You now have two 'a' characters, and one 'b' character.
Take five characters from the right of s. You now have four 'a' characters, two 'b' characters, and two 'c' characters.
A total of 3 + 5 = 8 minutes is needed.
It can be proven that 8 is the minimum number of minutes needed.
Example 2:
Input: s = "a", k = 1
Output: -1
Explanation: It is not possible to take one 'b' or 'c' so return -1.
Solution
Method 1 - Sliding Window
Here is the approach:
- Initial Counts: Count the occurrences of each character (‘a’, ‘b’, ‘c’) in the string
s
using a dictionary. If any character has less thank
occurrences, it is impossible to meet the requirement, so return-1
. - Sliding Window: Use a sliding window approach to find the smallest window that does not meet the requirement. Maintain a window of characters and adjust it until you have at least
k
occurrences of each character. Keep track of the minimum window size needed to achieve the goal. - Adjust Window:
- Expand the window by including characters from the start of the string and decrement their counts.
- If the count of any character goes below
k
, contract the window from the left until the count meets the requirement again. - Record the minimum window size that needs to be excluded.
Code
Java
class Solution {
public int takeCharacters(String s, int k) {
int n = s.length();
int left = 0, ans = n + 1, windowSz = 0;
Map<Character, Integer> charCnt = new HashMap<>();
// Count total occurrences of each character
for (int i = 0; i < n; i++) {
charCnt.put(s.charAt(i), charCnt.getOrDefault(s.charAt(i), 0) + 1);
}
// If any character count is less than k, return -1
if (charCnt.getOrDefault('a', 0) < k || charCnt.getOrDefault('b', 0) < k || charCnt.getOrDefault('c', 0) < k) {
return -1;
}
for (int right = 0; right < n; right++) {
char curr = s.charAt(right);
charCnt.put(curr, charCnt.get(curr) - 1);
windowSz++;
// Shrink the window until we fulfill the requirement
while (charCnt.get(curr) < k) {
charCnt.put(s.charAt(left), charCnt.get(s.charAt(left)) + 1);
windowSz--;
left++;
}
ans = Math.min(ans, n - windowSz);
}
return ans;
}
}
Python
class Solution:
def takeCharacters(self, s: str, k: int) -> int:
length = len(s)
left, ans, windowSz = 0, length + 1, 0
charCnt: Dict[str, int] = {'a': 0, 'b': 0, 'c': 0}
# Count total occurrences of each character
for char in s:
charCnt[char] += 1
# If any character count is less than k, return -1
if charCnt['a'] < k or charCnt['b'] < k or charCnt['c'] < k:
return -1
for right in range(length):
curr = s[right]
charCnt[curr] -= 1
windowSz += 1
# Shrink the window until we fulfill the requirement
while charCnt[curr] < k:
charCnt[s[left]] += 1
windowSz -= 1
left += 1
ans = min(ans, length - windowSz)
return ans
Complexity
- ⏰ Time complexity:
O(n)
, wheren
is the length of the strings
, since we process each character at most twice (once when expanding and once when contracting the window). - 🧺 Space complexity:
O(1)
, since the additional space used is constant (only a few variables and a fixed-size dictionary are used).