You are given a string containing only 4 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 the original string s balanced.
Return 0 if the string is already balanced.
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”.
Example 4:
Input: s = “QQQQ”
Output: 3
Explanation: We can replace the last 3 ‘Q’ to make s = “QWER”.
Constraints:
1 <= s.length <= 10^5
s.length is a multiple of 4
s contains only ‘Q’, ‘W’, ‘E’ and ‘R’.
一道周赛题,自己做的时候有点思路,可惜最后没能AC(遗憾.jpg)!
题目大意:给定一个字符串,字符串中只包含Q,W,E,R,4种字符,要求在字符串中找出一个最短的子字符串,使得使用另一个等长的字符串(字母组成随意)替换这个子字符串后可使得整个字符串的Q,W,E,R的数量相同。
个人思考:自己做的时候想到了应该开一个数组从前到后统计字符串中各种字符的数量,这一步主要是为了快速求出原字符串中字符i到字符j中各个字符的数量,但是没想到如何判定想要删除的子串是否符合条件。后来发现这个问题其实不难判断(看了大神的代码后),有了刚才的数组,能快速求解s[i,j]中各种字符的数量,虽然我们没办法根据这4个数中的最大值或最小值对最终答案做出什么判断,但是我们可以判断是否还能将子字符串进行缩短,这里判断的条件就是s[i,j]这个子串中的任意一种字符串的数量都要小于或者等于n/4,因为一旦将要换的子串确定了,各种字符的数量只会在未被换出的部分上进行增加,不会减少,所以这里只能小于或者等于。
解题思路:从答案出发,目标是找出一个子串,替换它然后使得整个串中的四个字母的数量相同,假设最后的结果是替换子串s[i,j](表示s中从第i个字符到第j个字符组成的子串),下面我们要做的就是如何搜索出i和j的值,使得j-i尽可能小,首先想到的就是暴力求解,枚举出所有的i和j,判断是否满足要求,在满足要求的基础上取最小值,时间复杂度
O
(
n
2
)
O(n^2)
O(n2),超时是逃不了的,但是这里很容易想到解决办法:二分搜索!,确定i,使用二分搜索j,时间复杂度
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),这样就能AC了。
下面是两种方法的代码:
#include <bits/stdc++.h>
using namespace std;
int x[100005][4];
int balancedString(string s) {
int n = s.size();
// x[i][0]表示前i个(计数从1开始)字符中Q的数量
for(int i = 0;i < n; i++){
for(int j = 0;j < 4; j++)
x[i+1][j] = x[i][j];
if(s[i] == 'Q') x[i+1][0]++;
if(s[i] == 'W') x[i+1][1]++;
if(s[i] == 'E') x[i+1][2]++;
if(s[i] == 'R') x[i+1][3]++;
}
int ans = INT_MAX;
for(int i = 0;i <= n; i++){
// 二分搜索
int lo = i;
int hi = n+1;
while(lo < hi){
int mid = (lo + hi) / 2;
int ok = 1;
for(int k = 0;k < 4; k++){
if(x[n][k] - x[mid][k] + x[i][k] > n/4){
ok = 0;
break;
}
}
if(ok == 1)
hi = mid;
else
lo = mid+1;
}
if(lo != n+1) // lo==n+1 表明在[i,n]中找不到有效值
ans = min(ans, lo-i);
// 暴力搜索法
// for(int j = i;j <= n; j++){
// int ok = 1;
// for(int k = 0;k < 4; k++){
// // 注意这里求的是删除字符串为(i,j]的情况,即左边不包括,右边包括
// if(x[n][k] - x[j][k] + x[i][k] > n/4){
// ok = 0;
// break;
// }
// }
// if(ok == 1)
// ans = min(ans, j-i); // 这里不是j-i+1,原因看上面
// }
}
return ans;
}
int main(int argc, char const *argv[])
{
cout << balancedString("QWER") << endl;
return 0;
}