56 两数之和
原题网址: http://www.lintcode.com/zh-cn/problem/two-sum/#
给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。
你需要实现的函数twoSum
需要返回这两个数的下标, 并且第一个下标小于第二个下标。注意这里下标的范围是 0 到 n-1。
注意事项
你可以假设只有一组答案。
给出 numbers = [2, 7, 11, 15]
, target = 9
, 返回 [0, 1]
.
Either of the following solutions are acceptable:
- O(n) Space, O(nlogn) Time
- O(n) Space, O(n) Time
1 class Solution { 2 public: 3 /** 4 * @param numbers: An array of Integer 5 * @param target: target = numbers[index1] + numbers[index2] 6 * @return: [index1 + 1, index2 + 1] (index1 < index2) 7 */ 8 vector<int> twoSum(vector<int> &numbers, int target) { 9 // write your code here 10 vector<int> result; 11 int size=numbers.size(); 12 13 for (int i=0;i<size;i++) 14 { 15 16 for (int j=i+1;j<size;j++) 17 { 18 19 int sum=numbers[i]+numbers[j]; 20 if (sum==target) 21 { 22 result.push_back(i); 23 result.push_back(j); 24 return result; 25 } 26 } 27 } 28 29 return result; 30 } 31 };
挑战:
参考 https://www.cnblogs.com/eudiwffe/p/6282635.html
https://www.cnblogs.com/libaoquan/p/6808064.html
C++ map注意事项 count与find
常见的思路是:两层for循环,任意两个数组合求其和,判断是否等于给定的target。但这样太慢,需要O(n^2)的时间,O(1)的额外空间。可以反过来思考,假如当前选择了一个数字a,那么为了满足条件,另一个数字b必须满足:b=targe-a,即在数组中寻找是否存在b。
如何快速寻找数组中是否存在一个数字b?假如数组是有序的,可以使用二分查找方法,其查找时间复杂度是O(logn)。然而题目并没给定这个条件。如果对数组排序,首先就要O(nlogn)的时间进行排序,并且排序后,数字的原始下标也要保存,显然需要O(nlogn)的时间以及O(n)的空间,并不是最好的方法。
如何对一个数组进行快速查找一个元素?算法中提供了一种方法——哈希(Hash),即对数组中的每个元素按照某种方法(hash function)计算其“唯一”值id(称为哈希值),存储在新的数组A中(一般称为哈希数组),并且其下标就是这个“唯一”值。那么如果访问A[id]存在,则这个元素存在,否则,原始数组中不存在该元素。由于数组是顺序存储的支持随机访问,所以查找一个元素是否在数组中,只需要O(1)的时间,但是在初始化哈希数组时,需要O(n)的时间和O(n)的空间。对于某些特定应用中,需要快速的时间,而对空间要求不苛刻时,哈希数组是一个非常好的方法。
1 class Solution { 2 public: 3 /** 4 * @param numbers: An array of Integer 5 * @param target: target = numbers[index1] + numbers[index2] 6 * @return: [index1 + 1, index2 + 1] (index1 < index2) 7 */ 8 vector<int> twoSum(vector<int> &numbers, int target) { 9 // write your code here 10 vector<int> result; 11 if (numbers.empty()) 12 { 13 return result; 14 } 15 int size=numbers.size(); 16 map<int,int> hashmap; 17 18 for (int i=0;i<size;i++) 19 { 20 hashmap.insert(pair<int,int>(numbers[i],i)); 21 } 22 23 for (int i=0;i<size;i++) 24 { 25 int temp=target-numbers[i]; 26 if (hashmap.count(temp)!=0&&hashmap[temp]!=i) //count查找元素出现次数,不为0说明存在; 27 { //hashmap[temp]!=i防止target为某数组元素倍数时返回一样的下标值; 28 result.push_back(i); 29 result.push_back(hashmap[temp]); 30 break; 31 } 32 } 33 if (result[0]>result[1]) //保证当target为数组中两个等值元素的和时下标顺序从小到大; 34 { 35 int t=result[0]; 36 result[0]=result[1]; 37 result[1]=t; 38 } 39 return result; 40 } 41 };
简单解释下最后一个if语句:
第一次在lintcode上测试时,当数据为[0,3,4,0] 和 0 时输出[3 0],结果错误。
数组中出现两个相同元素值,下标分别为0、3,创建hashmap时,下标为3的0无法插入,所以hashmap中有三对pair,(0,0)(3,1)(4,2)
第二个for循环查找map时,由于target=0,temp=0,在hashmap中count(temp)为1,但hashmap[temp]为0,等于i,不满足要求,循环继续。
直到i=3,temp=0,查找hashmap,找到了key等于0的pair,即(0,0),将下标3、 0插入result中。根据题意,要交换result中两个数据。