Replace the Substring for Balanced String
Link
Description
You are given a string s
of length n
containing only four kinds of characters: 'Q'
, 'W'
, 'E'
, and 'R'
.
A string is said to be balanced if each of its characters appears n / 4
times where n
is the length of the string.
Return the minimum length of the substring that can be replaced with any other string of the same length to make s
balanced. If s
is already balanced, return 0
.
Example 1:
- Input:
s = "QWER"
- Output:
0
- Explanation:
s is already balanced.
Example 2:
- Input:
s = "QQWE"
- Output:
1
- Explanation:
We need to replace a 'Q' to 'R', so that "RQWE" (or "QRWE") is balanced.
Example 3:
- Input:
s = "QQQW"
- Output:
2
- Explanation:
We can replace the first "QQ" to "ER".
Constraints:
n == s.length
4 <= n <= 10^5
n
is a multiple of 4
.
s
contains only 'Q'
, 'W'
, 'E'
, and 'R'
.
Solution
Way 1
| class Solution {
private:
// Helper method to check
// if the current window leads to a balanced string outside the window
bool check(vector<int>& cnts, int len, int require) {
/*
cnts: A vector of integers representing
the counts of each character ('Q', 'W', 'E', 'R')
outside the current sliding window.
len: The length of the current sliding window.
This is essentially the number of characters
that can be replaced to try and balance the string.
require: The required count of each character for the string to be balanced.
*/
// Track total adjustments needed to balance the string
int totalAdjustments = 0;
for (int i = 0; i < 4; i++) {
// If any character's count outside the window is more than required
if (cnts[i] > require) return false;
// Add needed adjustments to achieve balance
totalAdjustments += max(0, require - cnts[i]);
}
// Check if adjustments can be made within the current window length
return totalAdjustments <= len;
}
public:
int balancedString(string s) {
// Size of the input string
int n = s.size();
// Vector to map characters 'Q', 'W', 'E', 'R' to 0, 1, 2, 3
vector<int> arr(n);
// Vector to store counts of each character
vector<int> cnts(4, 0);
// Initialize character counts and mapping
for (int i = 0; i < n; i++) {
if (s[i] == 'Q') arr[i] = 0;
else if (s[i] == 'W') arr[i] = 1;
else if (s[i] == 'E') arr[i] = 2;
else if (s[i] == 'R') arr[i] = 3;
cnts[arr[i]]++;
}
// The required count of each character for the string to be balanced
int require = n / 4;
// Initialize the answer to the maximum possible value
// (length of the string)
int res = n;
// Use a sliding window approach to find the minimum length of substring to replace
for (int left = 0, right = 0; left < n; left++) {
// Expand the window to the right
// until the condition is met or the end of the string is reached
while (right < n && !check(cnts, right - left, require)) {
// Decrease the count of the character going into the window
cnts[arr[right]]--;
right++;
}
// If the condition is met,
// update the answer with the minimum window length
if (check(cnts, right - left, require)) {
res = min(res, right - left);
}
// Include the character at the current left of the window back into counts
cnts[arr[left]]++;
}
return res;
}
};
|
Way 2
See reference (Chinese).
| class Solution {
public:
int balancedString(string s) {
int n = s.size();
vector<int> arr(n);
vector<int> cnts(4, 0);
for (int i = 0; i < n; i++) {
switch (s[i]) {
case 'Q': arr[i] = 0; break;
case 'W': arr[i] = 1; break;
case 'E': arr[i] = 2; break;
default: arr[i] = 3; break;
}
cnts[arr[i]]++;
}
int require = n / 4;
if (cnts[0] == require && cnts[1] == require
&& cnts[2] == require && cnts[3] == require) {
return 0;
}
int res = n, left = 0;
for (int right = 0; right < n; right++) {
cnts[arr[right]]--;
while (cnts[0] <= require && cnts[1] <= require
&& cnts[2] <= require && cnts[3] <= require) {
res = min(res, right - left + 1);
cnts[arr[left]]++;
left++;
}
}
return res;
}
};
|
Sliding Window to Find Minimum Substring Length:
The core of this solution lies in the sliding window approach, where two pointers (left
and right
) are used to dynamically adjust the window size and find the smallest possible substring that can be replaced to balance the string. The right
pointer expands the window by moving to the right, and for each new position of right
, the character count is decremented (cnts[arr[right]]--
), effectively removing that character from consideration (assuming it could be part of the replaced substring).
Inside the loop, there's a nested while
loop that checks if the string, excluding the current window, is balanced (i.e., the count of each character is less than or equal to require
). If the condition is true, it tries to shrink the window from the left (by incrementing left
and adjusting counts accordingly) while maintaining the balance condition. During this process, it updates res
, the result variable, to hold the minimum length of the substring found that can be replaced to achieve balance.
By incrementing left
inside the while
loop only when the string excluding the current window is balanced, it ensures that the window size is as small as possible. The res
variable is updated with the minimum window size found during this process (right - left + 1
).
Complexity:
- Time Complexity: \(O(n)\), where \(n\) is the length of the input string. This reflects the efficient linear traversal of the input;
- Space Complexity: \(O(n)\), mainly due to the additional array (
arr
) used for character mapping. The rest of the auxiliary space usage is constant.