1102 A-B数对
这道题我早就做过了,但是因为今天研究了hash所以必须得来复习复习
我们得先明白题意,就是说输入n c 然后输入n个数枚举ab,是使得a-b=c
O(n^2)思路
这种思路是暴力进行枚举,朴素算法二重循环,这样做肯定会超时,这个题肯定没有这么简单的
O(nlogn)思路
利用二分思想一次循环枚举b,中间二分找c然后再相加判断a就好了
O(n)思路
优化一点的算法,就是用桶保存每一个数,这样的话我们只需要枚举b,然后判断一下c是不是存在就好了,这样时间复杂度会很低,但同时空间复杂度会很高,就会MLE
hash
hash才是我们的正解,才是我们应该做的,是这些解法里面最优秀的,那么怎么进行实现呢。
我们前面谈桶的时候,代价是用空间换时间,空间代价非常的高,hash就避免了这一点。
其实我们可以发现,桶数组很多桶会空,也就是说浪费空间了,比如四个数 2 4 7 10001,如果用桶的话我们就得开10001但是用hash只需要4个
2%4=2 4%4=0 7%4=3 10001%4=1
其实存hash的就是%一个数而已,但是%的过程中这个位置如果有数,那么就放后面,这就是取余法和再hash法
还有我们取余的数通常就是一个质数,1000003
1.输入然后映射散列表
2.映射过程中进行解决冲突
3.统计查找,也就是调用散列表
---------------重新-----------
最简单的做法就是暴力
当然暴力 肯定不是正解
还有一些二分了 桶了的
经过一些沉淀什么的,hash是这个题的正解
hash是一个函数,是一种映射,他表示的是一种关系的对应
他解决了桶的代价,有很多无用的空桶,我们需要将这些桶处理,因为他们太占空间,这就是唯一的缺点
hash的对应关系%一个数而已,但是%的过程中这个位置如果有数,那么就放后面,这就是取余法和再hash法
步骤就是三个
:
1.输入然后映射,预处理
2.解决冲突,也就是hash重复的函数值
3.统计查找,根据题目进行寻找
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define p 1000003//这就是我们需要取余的数
#define hash(a) a%p//hash函数
using namespace std;
long long n,m,a[p],ans;
struct node{
long long x;//这个位置对应的数
int y;//次数
}h[p];
int findd(long long x)
{//hash关键字,避免冲突的
int y=hash(abs(x));//获取hash值
while(h[y].x&&h[y].x!=x) y=hash(++y);
//避免冲突,往一个存
return y;
}
void push(long long x)
{//映射散列表
int y=findd(x);
h[y].y++;
h[y].x=x;
//存储再散列表中然后次数加一
}
int check(long long x)
{//统计次数
return h[findd(x)].y;
}
int main()
{
cin>>n>>m;
for(long long i=1;i<=n;i++)
cin>>a[i],push(a[i]);
for(long long i=1;i<=n;i++)
ans+=check(a[i]-m);//统计出现次数
cout<<ans<<endl;
return 0;
}