LeetCode题解:twoSum
LeetCode题解
说明:本人不是什么算法高手,部分内容参考了Google、stackoverflow、segmentfault中得到的一些解答或者代码。之所以去做Leetcode上的题是因为毕业工作后对算法有了新的认知。工作时发现虽然不是所有的算法都用得到,有些算法也已经封装好了只需要调用API就可以了。但是在有些时候当你不得不自己写算法的时候,你就会发现算法重要性,它不仅能让你很好的解决问题而且对你解决一起其它问题带来一些很好的思路的引导,以下代码都测试通过。
TwoSum
在官方中问题的描述是这样的:
Given an array of integers, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
也就是给你一个整型数组,找到这个数组中两数之和与所给目标数相等的数。并且返回这两个数的位置小标(不是基于0),而且这两个小标第一个必须比第二个小,你可以假定这个数组中只存在一组符合条件的情况。
一个不完全错误的解决方法:
下面给出这个问题在特殊情况下的解决方案。假如所给的数组是一个有序的数组,那么问题就简单多了。我们可以通过首尾同时逼近来解决,代码如下:
/*----------------------------------------------------- 参数: vector<int> &numbers //所给的数组 当数组中只有一个元素的时候返回一个空的vector<int> int target //所给的目标 返回值: vector<int> //两个下标位置 ------------------------------------------------------*/vector<int> twoSum(vector<int> &numbers, int target) { vector<int> result; unsigned int low=0, high = numbers.size()-1; while (low < high){ if (numbers[low] + numbers[high] == target){result.push_back(low+1);result.push_back(high+1);return result; }else{numbers[low] + numbers[high] > target ? high-- : low++; } } return result;}
但是已经说过了这是一个不完全错误的解决方法,官方并没有限定数组是有序的。如果我们先使用STL中自带的排序算法先排序,然后在采用这种方法,能解决问题。但是排序本身的最好的平均复杂度为O(n*log2n),然后再加上遍历的复杂度,肯定会有更好的解决方法。
更一般性的解决方法:
相比与基于有序数组的解决方法,更为一般的情况是所给的数组并不会是有序的,下面给出一般性的解决方法:
/*--------------------------------------------------------------- 参数: vector<int> &numbers //所给的数组 当数组中只有一个元素的时候返回一个空的vector<int> int target //所给的目标 返回值: vector<int> //两个下标位置 : ----------------------------------------------------------------*/vector<int> twoSum(vector<int> &numbers, int target) { unordered_map<int, int> m; vector<int> result; for(unsigned int i=0; i< numbers.size(); i++){ // not found the second one if (m.find(numbers[i])==m.end() ) { // store the first one poisition into the second one's keym[target - numbers[i]] = i; }else { // found the second oneresult.push_back(m[numbers[i]]+1);result.push_back(i+1);break; } } return result;}
方法的原理很明了,就是从头遍历所给的数组,遍历第一个元素的时候将target - numbers[i]作为键值i作为值存入类型为unordered_map<int>的m中,遍历后面的元素的时候我们现在m中插入有没有键值为当前元素numbers[i]的元素,如果存在那么m中所找到元素的值以及当前的位置i就是最终的位置。例如官方给的示例,第一次我们执行循环体内的判断时因为m为空这个肯定为true,我们在m中加入记录m[7] = 2,当我们第二次遍历执行时为false,m中存在m[7],这表明之前已经有与7想匹配的元素加入了m,而那个元素的位置就是m[7]的值,所以符合条件的元素位置就是m[7]+1,i+1 。