尺取法的思想
尺取法的思路非常简单:有一个数列a,要查找一对满足条件的数。
这个时候我们建两个指针i和j,i指向0,j指向n-1(n为a的元素个数)。
接下来,我们只需要根据需要,调整指针i和j,使a[i]和a[j]满足对应的条件就行了。
这种方法的时间复杂度为。
估计这样说大家还不太明白。那么废话不多说,我们直接看例题。
例题
题目:分身数对
题目描述
给出n个不同的正整数a[1]~a[n],它们的值在1~1000000之间。再给定一个整数x,编程计算这样的数对个数(a[i],a[j]),1≤i<j≤n并且a[i]+a[j]=x。
输入输出格式
输入格式:
第1行1个正整数n,1≤n≤100000。
第2行n个正整数,表示元素a[1]~a[n],每两个数之间用一个空格分隔。
第3行1个正整数x,1≤x≤2000000。
输出格式:
一行一个整数,表示这样的数对个数。
输入输出样例
输入样例#1:
9
5 12 7 10 9 1 2 3 11
13
输出样例#1:
3
提示信息
【样例说明】
不同的和为13的数对是(12,1),(10,3)和(2,11),共3对
题解
其实这一道题就很适合用尺取法去做——先排序,再尺取就好了。
具体就看代码的注释。
#include<bits/stdc++.h>
using namespace std;
int n,m,a[100100],cnt;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
sort(a,a+n); //排序
int i=0,j=n-1; //两个指针
while(i<j){ //类似二分
if(a[i]+a[j]<m) ++i;
//如果两数加起来小于目标数,说明应该让其中一个数变大一点,使得两数之和为目标数。
//因为现在a数组是有序的,所以要增大一个数,只需让i++即可,因为此时a[i]<=a[i+1]。
else if(a[i]+a[j]>m) --j;
//同样的,如果两数之和大于目标数,就让一个数变小就好了。
else ++cnt,++i;
//否则的话两数之和恰好等于目标数,cnt++,再增大i,以免重复统计。
}
printf("%d\n",cnt); //输出这种数对的总数
}
总结
这就是尺取法了。尺取法易懂,而且高效。
可惜的是,大多数题都用不到尺取。
但是学多一点总是好的嘛!