编程之美之快速寻找满足条件的两个数

快速找出一个数组numbers中的两个数字,让这两个数字之和等于一个给定的值,假定该数组中存在至少一组符合要求的解。在leetcode上也有该题,描述为:Two Sum:Given an array of integers, find two numbers such that they add up to a specific target number.

编程之美上给出了两个可行的方法,下面分别描述

解放一:hash算法

简单的说就是对于每一个numbers[i],把tartget-numbers[i]存入hash表中,然后遍历数组numbers,对于numbers[i],如果发现numbers[i]存在于hash表中,则说明numbers中存在target-numbers[i]。对于此方法,如果hash表使用map实现,则时间复杂度是O(nlogn),虽然和解法二相同,但是在leetcode上提交仍然超时(可能是我写的有问题),如果使用std::tr1::unordered_map(一种hash_map),时间复杂度是O(n),但是leetcode不支持,这里使用std::tr1::unordered_map,只是为了说明该算法,大家也可以使用普通的map,代码如下:

#include <iostream>
#include <tr1/unordered_map>
#include <vector>
#include <assert.h>
using namespace std;

bool isExist(tr1::unordered_map<int,int>& hash,int value,int index)
{
	tr1::unordered_map<int,int>::iterator iter = hash.begin();
	for(;iter != hash.end();iter++)
	{
		if(iter->first == value && iter->second != index)return true;//判断value是否存在,加上index是为了防止两个加数相等但只出现一次,比如5+5==10,但只有一个5
	}
	return false;
}
vector<int> twoSum(vector<int> &numbers, int target) {
	vector<int> res;
	int i,size = numbers.size();
	std::tr1::unordered_map<int,int> hash;
	for(i=0;i<size;i++)hash[target - numbers[i]] = i;//把待查找的另一半加入hash
	for(i=0;i<size;i++)
	{
		if(isExist(hash,numbers[i],i))//如果自己在hash中,则表明自己是另一半加入的,则另一半存在
		{
			int begin = hash[target-numbers[i]] > hash[numbers[i]] ? hash[numbers[i]] : hash[target-numbers[i]];
			int end = hash[target-numbers[i]] > hash[numbers[i]] ? hash[target-numbers[i]] : hash[numbers[i]];
			res.push_back(begin+1);//把两个数的位置存入结果
			res.push_back(end+1);
			break;
		}
	}
	return res;
}
解法二:排序法

简单的说,就是对原数据进行排序,然后用两个指针从两头分别进行扫描,如果和大于目标,则后面指针前移,反之,前面指针后移。针对leetcode上需要求两个数下标的情况,则用结构体保存原来的下标,具体代码如下:

struct node
{
	int value;
	int index;//在数组中的原来位置
};
bool operator<(const node& a,const node& b)
{
	return a.value < b.value;
}
vector<int> twoSum(vector<int> &numbers, int target) {
	int i,j,size = numbers.size();
	vector<node> data(size);
	for(i=0;i<size;i++)
	{
		data[i].value = numbers[i];
		data[i].index = i+1;
	}
	sort(data.begin(),data.end());
	i=0;
	j=size-1;
	vector<int> res;
	while(i < j)
	{
		if(data[i].value + data[j].value < target)i++;
		else if(data[i].value + data[j].value > target)j--;
		else
		{
			int begin = data[i].index > data[j].index ? data[j].index : data[i].index;
			int end = data[i].index > data[j].index ? data[i].index : data[j].index;
			res.push_back(begin);
			res.push_back(end);
			break;
		}
	}
	numbers.clear();
	return res;
}
代码如有问题,请指正,谢谢。下一篇会接着分析3个数的和、4个数的和



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值