不重复打印排序数组中相加和为给定值的所有二元组

4 篇文章 0 订阅

题目描述
给定排序数组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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值