连续两天的周赛,双周赛都用到了,记录一下。
1653. 使字符串平衡的最少删除次数
给你一个字符串 s ,它仅包含字符 ‘a’ 和 'b’ 。
你可以删除 s 中任意数目的字符,使得 s 平衡 。我们称 s 平衡的 当不存在下标对 (i,j) 满足 i < j 且 s[i] = ‘b’ 同时 s[j]= ‘a’ 。
请你返回使 s 平衡 的 最少 删除次数。
输入:s = "aababbab"
输出:2
解释:你可以选择以下任意一种方案:
下标从 0 开始,删除第 2 和第 6 个字符("aababbab" -> "aaabbb"),
下标从 0 开始,删除第 3 和第 6 个字符("aababbab" -> "aabbbb")。
class Solution {
public:
int minimumDeletions(string s) {
int len = s.size();
vector<int>pre(len,0), suf(len,0);
for(int i = 0; i < len; i++){
if(i > 0) pre[i] = pre[i-1];
pre[i] += s[i] =='b';
}
for(int i = len-1; i>=0; i--){
if(i < len-1) suf[i] = suf[i+1];
suf[i] += s[i] =='a';
}
int ans = min(pre[len-1], suf[0]);
for(int i = 1; i < len; i++){
ans = min(ans, pre[i-1]+suf[i]);
}
return ans;
}
};
1658. 将 x 减到 0 的最小操作数
给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -1 。
示例 1:
输入:nums = [1,1,4,2,3], x = 5
输出:2
解释:最佳解决方案是移除后两个元素,将 x 减到 0 。
class Solution {
public:
int minOperations(vector<int>& nums, int x) {
int len = nums.size();
vector<long long>pre(len), suf(len);
int ant = INT_MAX;
for(int i = 0; i < len; i++){
if(i) pre[i] = pre[i-1];
pre[i]+=nums[i];
if(pre[i] == x) ant = min(ant, i+1);
}
for(int i = len-1; i>=0; i--){
if(i < len-1) suf[i] = suf[i+1];
suf[i] += nums[i];
if(suf[i] == x) ant = min(ant, len-i);
}
// 第一种写法,超时,两层循环, pre递增,suf递增,时间负载度o(n^2)
// for(int i = 0; i < len; i++){
// if(pre[i] > x) break;
// else{
// int j = len-1;
// while(j > i && pre[i] + suf[j] < x)j--;
// if(j > i && pre[i] + suf[j] == x)ant = min(ant, i + 1 + len-j);
// }
// }
// 第二种写法,ac 改变suf遍历顺序,递减遍历,因为pre也是递增遍历,j永远不回头,时间复杂度o(n)
for(int i = 0, j = 1; i + 1 < len; i += 1){
j = max(j, i + 1);
while(j < len and pre[i] + suf[j] > x) j += 1;
if(j < len and pre[i] + suf[j] == x) ant = min(ant, i + 1 + len - j);
}
return ant == INT_MAX?-1:ant;
}
};
—注:本题也可以使用滑动窗口,找到sum-x的连续窗口。
补充,滑动窗口实现
class Solution {
public:
int minOperations(vector<int>& nums, int x) {
int target = -x;
for(const int &a:nums){
target+=a;
}
if(target < 0) return -1;
int left = 0, right = 0, sum = 0,ans = INT_MIN;
int len = nums.size();
while(left < len){
if(right < len){
sum += nums[right++];
}
while(sum >= target){
// 记录最大的窗口尺寸
if(sum == target) ans = max(ans, right-left);
sum-=nums[left++];
}
// 这里可以直接break了,下面写法也ac
if(right == len)left++;
// if(right == len) break;
}
int res = ans==INT_MIN?-1: len-ans;
return res;
}
};