概念
度娘解释:尺取法,一种比较基础的算法,一般用来解决具有单调性的区间问题。通常是根据实际情况不断地推进区间左右端点以得出答案,比直接暴力枚举区间效率高很多,尤其是数据量大的时候。所以说尺取法是一种高效的枚举区间的方法,是一种技巧,一般用于求取有一定限制的区间个数或最短的区间等等。
通俗来说:给定一个序列,当数据量庞大且问题与序列的区间有关时,应用尺取法(即操作两个变量,使用一层循环扫描区间)可以优化时间复杂度O(n2)–>O(n)。
代码实现
优化前
for(int i=0;i<n;i++){//i从头扫到尾
for(int j=n-1;j>=0;j--){//j从尾扫到头
...
}
}
优化后(反向扫描)
//使用for循环
for(int i=0,j=n-1;i<j;i++,j--){
...
}
//使用while循环
int i=0,j=n-1;
while(i<j){
...
i++;
j--;
}
尺取法使用时应注意以下三点:
① 尺取法的应用范围?
一般:连续区间内求解(寻找区间,数组去重,多指针问题)
② 区间的端点何时推进以及如何推进?
满足:更新
不满足:推进
根据题意判断如何推进
③ 何时结束区间的枚举?
反向扫描(左右指针)
举个栗子
题目:输入n(1e5)个整数,放在数组a[]中,找出其中的两个数,它们之和等于整数m(假设一定有解)
说明:第一行:数组a[];第二行:m
样例输入:
21 4 5 6 13 65 32 9 23
28 //m为28
样例输出:
5 23 //5+23=28
四种解决方案
- 二重循环暴力搜索:时间复杂度O(n2)
- 二分法:先从小到大排序,时间复杂度O(nlog2n)。遍历数组a[i],在大于a[i]的数中二分查找等于m-a[i]的数,时间复杂度O(nlog2n)。总时间复杂度O(nlog2n)。
- 哈希:分配一个哈希空间s,把n个数放进去,遍历a[]中的n个数,例a[i],检查m-a[i]在s中是否有值,时间复杂度O(n)。很快,但需要额外的很大的哈希空间。
- 尺取法:从小到大排序,时间复杂度O(nlog2n)。
定义两个变量i=0,j=n-1,如果a[i]+a[j]>m,则j–,如果a[i]+a[j]<m,则i++,直至a[i]+a[j]=m,时间复杂度O(n)。总 时间复杂度O(nlog2n)。
尺取法代码实现
#include<iostream>
#include<algorithm>
using namespace std;
void find_sum(int a[],int n,int m){
sort(a,a+n);
int i=0,j=n-1;
while(i<j){
int sum=a[i]+a[j];
if(sum>m){
j--;
}
if(sum<m){
i++;
}
if(sum==m){
printf("%d %d\n",a[i],a[j]);
i++;
}
}
}
完整代码
int main(){
int a[100],n=0,m,i=0;
while(getchar()!='\n'){
scanf("%d",&a[i]);
n++;
i++;
}
scanf("%d",&m);
find_sum(a,n,m);
return 0;
}
同向扫描(快慢指针)
题目:给定长度为n的数组a[]和一个数s,在这个数组中找一个区间,使这个区间的元素之和等于s,输出区间的起点和终点。
说明:第一行:一个数n,第二行:数组a[],第三行:目标区间和s
样例输入:
15
6 1 2 3 4 6 4 2 8 9 10 11 12 13 14
6
样例输出:
0 0
1 3
5 5
6 7
定义两个变量i,j均从头部开始遍历,判断区间[i,j]数组元素的和是否为s
初始值:i=0,j=0,sum=a[0](sum为区间[i,j]数组元素和)
如果sum=s,输出一组解,sum-=a[i],i++;
如果sum>s,sum-=a[i],i++;
如果sum<s,j++,sum+=a[j];
尺取法代码实现
void find_sum(int a[],int n,int s){
int i=0,j=0,sum=a[0];
while(j<n){
if(sum>=s){
if(sum==s){
printf("%d %d\n",i,j);
}
sum-=a[i];
i++;
if(i>j){ //防止i超过j
sum=a[i];
j++;
}
}
if(sum<s){
j++;
sum+=a[j];
}
}
}
完整代码
int main(){
int a[100],n,s;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
scanf("%d",&s);
find_sum(a,n,s);
return 0;
}
~~纯纯小白一枚,如果文章有错误或需要改进的地方,欢迎并感谢提出~