题目描述
给定排序数组arr和整数k,不重复打印arr中所有相加和为k的不降序二元组
例如, arr = [-8, -4, -3, 0, 1, 2, 4, 5, 8, 9], k = 10,打印结果为:
1, 9
2, 8
[要求]
时间复杂度为O(n),空间复杂度为O(1)
输入描述:
第一行有两个整数n, k
接下来一行有n个整数表示数组内的元素
输出描述:
输出若干行,每行两个整数表示答案
按二元组从小到大的顺序输出(二元组大小比较方式为每个依次比较二元组内每个数)
示例1
输入
10 10
-8 -4 -3 0 1 2 4 5 8 9
输出
1 9
2 8
思路一:尝试n*logn时间复杂度能不能通过,利用set去重,结果自己写的二分查找还是超时了,顺便保存一下递归的与非递归的二分查找。
#include <set>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int64_t binarySearch(int start,int end,vector<int64_t> num,int64_t k)
{
int mid=(end-start)/2+start;
if(start>end) return -1;
if(num[mid]==k) return mid;
else if(num[mid]>k) return binarySearch(start,mid-1,num,k);
else return binarySearch(mid+1,end,num,k);
}
int64_t binarySearch(vector<int64_t> array, int len, int value)
{
if (array.empty())
return -1;
int low = 0;
int high = len - 1;
while (low <= high)
{
int mid = low + (high - low) / 2;
if (array[mid] == value)
return mid;
else if (array[mid] > value)
high = mid - 1;
else
low = mid + 1;
}
return -1;
}
int main()
{
int64_t n,k;
cin>>n>>k;
set<pair<int64_t,int64_t>> ans;
vector<int64_t>num(n);
for(int i=0;i<n;++i)
cin>>num[i];
for(int i=0;i<n-1;++i)
{
int64_t res=k-num[i];
int64_t j=binarySearch(i+1,n-1,num,res);
if(i<j&&j<n) ans.insert(make_pair(num[i],num[j]));
}
for(set<pair<int64_t,int64_t>>::iterator it=ans.begin();it!=ans.end();++it)
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
思路二:
利用STL的set进行查找,时间复杂度也是n*logn,毕竟这个查找的logn还是很优秀的
#include <set>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
int64_t n,k;
cin>>n>>k;
set<int64_t> num;
set<pair<int64_t,int64_t>> ans;
for(int i=0;i<n;++i)
{
int64_t temp;
cin>>temp;
/* 先检查再插入,避免5+5=10的5是同一个元素,注意pair里俩元素的大小顺序 */
if(num.count(k-temp)) ans.insert(make_pair(min(temp,k-temp),max(temp,k-temp)));
num.insert(temp);
}
for(set<pair<int64_t,int64_t>>::iterator it=ans.begin();it!=ans.end();++it)
cout<<it->first<<" "<<it->second<<endl;
return 0;
}
思路三:
使用hash_set,查找的时间复杂度为O(1),这样整体时间复杂度为O(n)
但是由于<hasn_set>(还有<hash_map>)等头文件不是标准c++头文件,需要using namespace stdext;并且在线编译器似乎不支持这样。
偶然在c++官方文档中发现hash_set和hash_map现在替代为unordered_map和unordered_set,只需<unordered_set>头文件即可
另外补充一点,map和set基于红黑树,很多操作都是logn,并且他在插入是能维持有序
定义set<int,greater>即可实现从大到小排序
map类同,定义的时候map<int,int,greater >即可实现按照key从大到小排序。
当然需要从小到大的顺序的话,使用reverse_iterator逆序迭代器对rbegin,rend进行遍历即可
#include <unordered_set>
#include <set>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
int64_t n,k;
cin>>n>>k;
set<pair<int64_t,int64_t>> ans;
unordered_set<int64_t> num;
for(int i=0;i<n;++i)
{
int64_t temp;
cin>>temp;
if(num.find(k-temp)!=num.end()) ans.insert(make_pair(min(temp,k-temp),max(temp,k-temp)));
num.insert(temp);
}
for(set<pair<int64_t,int64_t>>::iterator it=ans.begin();it!=ans.end();++it)
cout<<it->first<<" "<<it->second<<endl;
return 0;
}