由题意可知,此题即是要你求出差值为k的不重复数字对个数。
输入样例中,1 5 3 4 2中1 3是一对,5 3 是一对,4 2是一对。
很显然,最常规最暴力的解法是对n个元素进行二层遍历,之后再去判断重复,若之前已经有过这个数字对则不保存,如果没有的话则保存到开辟的二维数组中。
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(a[i]+k==a[j])
if(无重复[在二维数组中进行遍历])保存到开辟的二维数组。
else continue;
大体就是这一个思想,而这题的数据范围是n>=1,n<=100000,这个算法的时间的其实是o(n的三次方)[立方阶时间复杂度],已知计算机的处理速度一般为1秒运算5*10的八次方,题目一般限制为1秒,显而易见这肯定会超时。立方阶的时间复杂度能处理的数据范围大于在n<=300。
所以这时候我们可以对这个算法进行优化和改进,其实判断重复的这个完全可以用c++的stl类库,set集合容器有一个比较好的特性是每次插入元素的时候容器内已经有了这个元素的话则无法再插入这个元素(可以把set想象成一个集合),而这个容器提供了几个函数让我们可以增删查。set::insert(插),set::erase(删),set::find(查),内部是由平衡二叉树实现的(了解),所以我们需要来了解一下这个set的用法,
#include <iostream>//c++的标准输入输出头文件
#include <set> //set容器类库
using namespace std;//c++使用std命名空间,(加上就行)
int main()
{
set<int> myset;//定义一个内容元素类型为int的myset容器
myset.insert(1);//插入1这个元素
myset.insert(2);//插入2这个元素
myset.insert(3);//不打了。。
myset.erase(3);//删除容器内3这个元素
if(myset.find(3)!=myset.end())cout<<"找到了3"<<endl;//endl是c++的换行符
if(myset.find(2)!=myset.end())cout<<"找到了2"<<endl;
set<int>::iterator it;//set<int>类的迭代器,类似set的指针,遍历和修改的时候常用
for(it=myset.begin();it!=myset.end();it++)//myset.begin()返回的是set容器的第一个元素,myset.end()返回的容器的末,it++容器迭代器的更新。
{
cout<<*it<<endl;//输出迭代器所指向的容器元素内容
}
}
输出结果为,我不再说了,上面就是set的基本语法。
有了这个我们就可以对这题进行优化了。已知本题数据范围最大为100000,所以我们可以开一个这么大的数组,最好在全局变量里开数组,在主函数中开的数组不如全局变量的大,因为主函数存储的数据毕竟是在栈里存储的。
算法的思想就是减少枚举变量,前面不是两层for循环吗,其实你可以发现,如果我们只枚举a[i],比如a[i]=3,那么如果存在数对的话,这个数对肯定是(a[i],a[i]+k),那么问题就变成了查找a[i]+k是不是在集合里。这个程序不仅利用了set判断元素存在不存在,还利用了set去重的特性,时间复杂度为o(N),很优秀的时间复杂度,
#include <iostream>
#include <set>
#define M 100000
using namespace std;
int num[M];
set<int> myset;
int main()
{
int n,k,x,ans=0;
cin>>n>>k;
for(int i=0;i<n;i++)//set集合容器的输入
{
cin>>x;
myset.insert(x);
}
set<int>::iterator it;
for(it=myset.begin();it!=myset.end();it++)//迭代器遍历
{
if(myset.find(*(it)+k)!=myset.end())//查找a[i]+k是不是在容器内,如果有这个元素,find返回这个元素所在位置,如果没有这个元素的话,find()返回的是myset.end()
ans++;//有的话数字对个数++
}
cout<<ans;
}