题目的大概意思是在一个无序数组中找到两个数字的下标,使得这两个数字的和刚好为指定数。
最简单的解是暴力搜索法,代码如下:
class Solution1 {
public:
<span style="white-space:pre"> </span>vector<int> twoSum(vector<int>& nums, int target) {
<span style="white-space:pre"> </span>for (unsigned int i = 0;i < nums.size();i++)
<span style="white-space:pre"> </span>for (unsigned int t = i+1;t < nums.size();t++)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if (nums[i] + nums[t] == target)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>vector<int> res;
<span style="white-space:pre"> </span>res.push_back(i);
<span style="white-space:pre"> </span>res.push_back(t);
<span style="white-space:pre"> </span>return res;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return vector<int>();
<span style="white-space:pre"> </span>}
};
效果如下,因为时间复杂度是O(n^2),所以耗时很高
};
于是就有了改进思路:
1.对元素进行从小到大排序,时间复杂度O(nlgn)
2.设置头尾两个下标,尾下标从大到小,头下标每次从小到大
3.尾尾下标不必从最后一个开始递减,而是从k开始递减 k使得_numbers[k]+_numbers[0]<=target,因为如果一个数加上最小的数都比目标大,那结果肯定不包括这个数,这样就过滤掉了很多不可能的数字。
代码如下:
class Solution2 {
public:
<span style="white-space:pre"> </span>vector<int> twoSum(vector<int>& nums, int target) {
<span style="white-space:pre"> </span>vector<pair<int, unsigned int>> _numbers;
<span style="white-space:pre"> </span>vector<int> _res;
<span style="white-space:pre"> </span>unsigned int _count = 0;
<span style="white-space:pre"> </span>for_each(nums.begin(), nums.end(), [&_numbers, &_count](int a) {_numbers.push_back(make_pair(a, _count++));});
<span style="white-space:pre"> </span>sort(_numbers.begin(), _numbers.end(), [](pair<int, unsigned int> & a, pair<int, unsigned int> &b) {return a.first < b.first;});
<span style="white-space:pre"> </span>int _i_a = _numbers.size()-1;
<span style="white-space:pre"> </span>while (_numbers[_i_a].first+ _numbers[0].first > target&&_i_a >= 0)
<span style="white-space:pre"> </span>_i_a--;
<span style="white-space:pre"> </span>while (_i_a >= 0)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int _i_b = 0;
<span style="white-space:pre"> </span>int _result = target + 1;
<span style="white-space:pre"> </span>while ((_result=_numbers[_i_a].first + _numbers[_i_b].first) < target&&_i_b < _i_a)
<span style="white-space:pre"> </span>_i_b++;
<span style="white-space:pre"> </span>if (_result == target)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if (_numbers[_i_a].second < _numbers[_i_b].second)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>_res.push_back(_numbers[_i_a].second);
<span style="white-space:pre"> </span>_res.push_back(_numbers[_i_b].second);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>_res.push_back(_numbers[_i_b].second);
<span style="white-space:pre"> </span>_res.push_back(_numbers[_i_a].second);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return _res;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>_i_a--;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return _res;
<span style="white-space:pre"> </span>}
};
开始的foreach的时间复杂度为O(n),而排序算法的时间复杂度为O(nlgn),下面的搜索算法的时间复杂度最坏情况下为O(n^2)
性能如下:
另外还有一个更简洁的办法,利用map或者哈希的低时间复杂度,来对每个元素进行检测:
对于当前元素n,若在map中发现target-n这个数,那么就代表找到答案了,否则吧n放入map,继续检测下一个元素,代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> res;
unordered_map<int,int> items;
auto size = nums.size();
for (int i = 0;i < size;i++)
{
if (items.find(target - nums[i]) != items.end())
{
vector<int> res = { items[target - nums[i]] ,i };
return res;
}
else if(items.find(nums[i]) == items.end())
items[nums[i]] = i;
}
return vector<int>();
}
};
运行时间如下:
第四种方法:对数据进行排序后,使用一个头指针与一个尾指针,定义如下规则:
如果两个指针指向的数字之和小于target,则头指针向后移动,因为答案已经不可能包含当前头指针指向的数字
如果两个指针指向的数字之和大于target,则尾指针向前移动,英文答案已经不可能包含当前尾指针指向的数字
这样直到找到答案,时间复杂度为nlgn+n 即O(nlgn)
代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<pair<int, unsigned int>> _numbers;
vector<int> _res;
unsigned int _count = 0;
for_each(nums.begin(), nums.end(), [&_numbers, &_count](int a) {_numbers.push_back(make_pair(a, _count++));});
sort(_numbers.begin(), _numbers.end(), [](pair<int, unsigned int> & a, pair<int, unsigned int> &b) {return a.first < b.first;});
unsigned int start = 0, end = _numbers.size() - 1;
while (start < end)
{
auto sum = _numbers[start].first + _numbers[end].first;
if (sum < target)
start++;
else if (sum>target)
end--;
else
{
_res.push_back(_numbers[start].second);
_res.push_back(_numbers[end].second);
break;
}
}
return _res;
}
};