尺取
最经典的尺取题:
题目描述
给定一个长度为 N 的正整数序列(10 < N < 100 000),序列中的每个数字都小于等于 10000,以及一个正整数 S(S < 100 000 000)。编写一个程序,找到序列中长度最小的连续子序列,其元素和大于或等于 S。
输入
第一行是测试用例的数量。对于每个测试用例,程序需要从第一行读取数字 N 和 S,数字之间用空格分隔。第二行是该测试用例的序列数字,数字之间用空格分隔。输入以文件结束符结束。
输出
对于每个测试用例,程序需要在输出文件的单独一行打印结果。如果没有符合条件的子序列,输出 0。
样例输入
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
样例输出
3
思路:找满足条件的最小区间,尺取
代码:
#include <iostream>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int main(){
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++){
cin>>a[i];
}
int l=0,r=0,ans=1e5+5,sum=0;
while(1){
while(sum<m&&r<n){
sum+=a[r++];
}
if(sum<m) break;
while(sum>=m&&l<r){
ans=min(ans,r-l);
sum-=a[l++];
}
}
if(ans==1e5+5) cout<<0<<endl;
else cout<<ans<<endl;
}
return 0;
}
第二道是力扣的一道困难题:76. 最小覆盖子串 - 力扣(LeetCode)
但也是找最小区间,尺取解决
代码:
class Solution {
public:
string ss,tt;
int num_t[100];
bool is_Bao(int num_s[]){ //怎么用快速的方法判断区间是否满足条件
for(int i=0;i<80;i++){
if(num_s[i]<num_t[i])
return false;
}
return true;
}
string minWindow(string s, string t) {//找最小子串:那么就是尺取
int num_s[100];
for(int i=0;i<100;i++) num_s[i]=0;
//使用hash
int m=s.length();
int n=t.length();
long long right_ans=0;
for(int i=0;i<n;i++) num_t[t[i]-'A']++;
int l=0,r=0;
int minLen = 1e5+5;
int ans_l=0,ans_r=0;
while(1){
while(!is_Bao(num_s)&&r<m){
num_s[s[r]-'A']++;
r++;
}
if(!is_Bao(num_s)) break;
while(is_Bao(num_s)&&l<r){
if(r-l<minLen){
minLen=r-l;
ans_l=l;
ans_r=r;
}
num_s[s[l]-'A']--;
l++;
}
}
string ans="";
for(int i=ans_l;i<ans_r;i++){
ans+=s[i];
}
return ans;
}
};