Two Sum
(点击可以链接到leetcode OJ问题描述和代码提交页面)
<问题描述>
给定一个整形数组,需要从数组中找出两个整数,使得它们之和等于另外一个给定的整数
下面给出的twoSum函数应该返回需要找到的这两个整数对应的索引值,当然,这两个索引值index1 和 index2必须满足这样两个特性,index1必须小于index2 和 这两个索引都不是基于0的下标索引 (注:返回的索引是 在数组的下标索引值 + 1)
你可以假定对应的每一个输入有且仅有一个答案
输入 : numbers = {2, 7, 11, 15}, target = 9 (注 : 不要被这个样例输入迷惑, 输入的数组元素不一定是有序的)
输出 : index1 = 1, index 2 = 2
<问题分析>
1. 双层循环,O(n * n) 的时间复杂度,很清楚的思路,但是数组足够大的时候,太慢了吧,过不了 large input 的。
2. 如果数组是有序的,当然有比较好的 O(n)复杂度的算法,首尾同时遍历。
3. 如果直接在原始数组上排序,必然最后得到的索引是错误的(当然你要坑我的说,如果原始数组已经是非降序的,那另说)。因此我们另定义一个和原始数组一样的数组,在这个新数组上排序,然后查找,然后根据查找到的元素去元素数组上定位索引,为啥?上面说‘你可以假定对应的每一个输入,有且只有一个答案’,不存在两个答案。但是也要注意,可能这两个元素相同,如目标值是 10,要查找的两个元素是5, 5.
<Code>
class Solution { public: vector<int> twoSum(vector<int> &numbers, int target) { vector<int> answer(2, 0); vector<int> temp = numbers; sort(temp.begin(), temp.end()); int length = temp.size(); int left = 0; int right = length - 1; /* * 下面的while循环,只循环一次n数组 * 因为temp数组是有序的,首尾同时遍历, * 如果之和sum < target, 那么我们只能通过将左指示器向右移一位来增大 sum * 如果之和sum > target, 那么我们通过右指示器向左移一位来减小 sum * 必定有一个sum == target,此时break,退出循环 */ while (left < right) { int sum = temp[left] + temp[right]; if (sum == target) { break; } else if (sum < target) { ++ left; } else { -- right; } } /* * 略加注意如 目标值是 10,要查找的两个元素是5, 5 这样的情况,两个元素值相同 * */ for (int i = 0; i < length; ++ i) { if (temp[left] == numbers[i] || temp[right] == numbers[i]) { if (answer[0] == 0) { answer[0] = i + 1; } else { answer[1] = i + 1; break; } } } return answer; } };