滑动窗口,写判定当前子串是否包含所有的字母
#include <bits/stdc++.h>
using namespace std;
int num[26] = {0};
bool bingo() {
for(int i = 0; i < 26; i++) {
if(num[i] == 0)
return false;
}
return true;
}
int main() {
memset(num, 0, sizeof(num));
string s;
cin >> s;
int start = 0, res = INT_MAX;
for(int i = 0; i < s.size(); i++) {
num[s[i] - 'a'] += 1;
if(bingo()) {
res = min(res, i - start + 1);
while(start < i) {
num[s[start] - 'a'] -= 1;
start += 1;
if(!bingo())
break;
res = min(res, i - start + 1);
}
}
}
cout << res << endl;
return 0;
}
对数组数据按照从小打大排序,前缀和记录相邻数据之间的差值,经过k次操作如果需要相同数据出现的次数最多,那么肯定是变化为数组中已经存在的数字,以当前数组位置作为左端点,二分求解右端点的位置。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
long long f[maxn];
long long delta[maxn];
long long k;
bool judge(int l,int r) {
int mid = (l + r)>>1;
//处于[l, mid]区间的所有数变成mid需要的操作数
long long left = f[mid] * (mid - l + 1) - (delta[mid] - delta[l-1]);
//处于[mid + 1, r]区间的所有数变成mid需要的操作数
long long right = (delta[r] - delta[mid]) - (r - mid) * f[mid];
long long ans = left + right;
return ans <= k ? true : false;
}
int main() {
int n;
cin >> n >> k;
for(int i = 1; i <= n; i++)
cin >> f[i];
sort(f + 1, f + n + 1);
for(int i = 1; i <= n; i++)
delta[i] = delta[i - 1] + f[i];
int res = 0;
for(int i = 1; i <= n; i++) {
int l = i, r = n;
while(l < r) {
int mid = (l + r + 1)>>1;
if(judge(i, mid))
l = mid;
else
r = mid - 1;
}
res = max(res, r - i + 1);
}
cout << res << endl;
return 0;
}
第一遍写的思路是:统计连续的1和0的个数,1的个数为正数记录,0的个数为负数记录,之后遍历连续数组每个位置,以当前位置为起点,寻找最后的端点。但是总是超时,于是考虑能否二分,但是二分其实判定的函数时间复杂度也是O(n).之后再想,其实不需要做一个连续化,直接在原本数组上进行滑动窗口操作,即可判定。
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param n int
* @param m int
* @param a intvector
* @return int
*/
int solve(int n, int m, vector<int>& a) {
// write code here
int res = 0, sum = 0, start = 0, end = 0;
while(end < a.size()) {
while(end < a.size()) {
if(a[end] == 1)
sum = sum + 1;
else {
if(m > 0) {
m -= 1;
sum = sum + 1;
} else
break;
}
end = end + 1;
}
res = max(res, sum);
while(start < a.size() && m <= 0) {
if(a[start] == 1) {
sum -= 1;
} else {
m += 1;
sum -= 1;
}
start += 1;
}
}
return res;
}
};
滑动窗口,由于顺逆时针,所以数组元素要存储两遍,进行前后拼接形成循环
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> p;
int sum = 0;
for(int i = 0; i < n; i++) {
int a;
cin >> a;
p.emplace_back(a);
sum = sum + a;
}
int res = INT_MIN;
for(int i = 0; i < n; i++)
p.emplace_back(p[i]);
int start = 0, end = 0, sum1 = 0;
while(end < p.size()) {
while(end < p.size()) {
sum1 = sum1 + p[end];
res = max(res, min(sum - sum1, sum1));
end += 1;
if(sum1 * 2 >= sum)
break;
}
res = max(res, min(sum - sum1, sum1));
while(start < p.size() && sum1 * 2 >= sum) {
sum1 -= p[start];
start += 1;
}
}
cout << res << endl;
return 0;
}