Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
因为题目已经假设只有唯一解,所以不考虑有重复数字的情况。
解法一:
暴力搜索,穷举。时间复杂度O(n^2),空间复杂度O(1)。
解法二:
空间换时间。换个方向想,题目就是求目标值target和其中一个数A的差B在数组中的位置。维护数组中每个元素到索引的映射的最佳方法是什么? 一个哈希表,那么我就利用一个HashMap建立数组中数值和下标的关系。在一次迭代中,先在HashMap中寻找该差值是否存在,如果不存在就把数A及其下标存入HashMap;若是存在,就意味着已经得到最后的结果了。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, size_t> hashMap;
vector<int> result;
for (int i = 0; i < nums.size(); i++)
{
int remain = target - nums[i];
auto findIt = hashMap.find(remain);
if (findIt == hashMap.end())
{
hashMap.insert({ nums[i],i });
}
else
{
result.push_back(findIt->second);
result.push_back(i);
}
}
return result;
}
};
时间复杂度、空间复杂度都是O(n)。
解法三:排序+二分查找
先对数组排序。排序后将双指针指向头部与尾部元素,进行迭代。如果双指针指向元素之和大于目标和,则将尾部指针向前移一位,反之则将头部指针向后移一位,直到双指针指向元素之和等于目标和,记录这两个元素的值。
(排序非常直接的就意味着二分搜索。一次查一半,所以刚开始只用到了二分搜索。但是有个问题,二分搜索的步子太大,可能把目标值跳过,那么还要借鉴双指针的全盘扫描的特点。)
存在的问题:
排序的效率?
排序的如何得到正确的索引?
复制一份数组进行排序,然后用原数组查找得到索引。我在此使用的是multiset,利用它本身有序的特性。(以为不含重复数,但是提交时有测试用例不通过)
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
multiset<int> orderSet(nums.cbegin(), nums.cend());
vector<int> rsNum, result;
auto beg = orderSet.begin();
auto end = orderSet.end();
--end;
while (beg != end)
{
if (*beg + *end == target)
{
rsNum.push_back(*beg);
rsNum.push_back(*end);
break;
}
else if (*beg + *end > target)
{
--end;
}
else
{
++beg;
}
}
for (int i = 0,j=0; i < nums.size(); i++)
{
if (nums[i] == *beg || nums[i] == *end)
{
++j;
result.push_back(i);
if (j == 2)break;
}
}
return result;
}
};
//这道题使用map的话可能会更简洁
补上multimap版本:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
multimap <int, size_t> orderMap;
vector<int> result;
for (int i = 0; i < nums.size(); i++)
{
orderMap.insert({ nums[i],i });
}
auto beg = orderMap.begin();
auto end = orderMap.end();
--end;
while (beg != end)
{
if (beg->first + end->first == target)
{
result.push_back(beg->second);
result.push_back(end->second);
break;
}
else if (beg->first + end->first > target)
{
--end;
}
else
{
++beg;
}
}
return result;
}
};
总结综合结果来看,第二种方法是最快的。