leetcode 1. Two Sum
Question
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.
Example
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
问题
给定一个整数数组和一个目标整数,返回两个索引值,使得这两个索引对应的两个数组元素的和为目标数组。假设只有唯一解。
分析
首先想到的肯定是常规的两重遍历法,时间复杂度为O(
n2
);
倒排索引法(inverted index):创建一个map,把数组的value作为key,把数组的key作为value。一次遍历数组nums,通过倒排索引的map查找key为target - nums[i]的value j,则[i, j]即为所求索引对;
首尾指针夹逼法:首先将数组排序(注意要保存原索引),然后首尾两个指针分别向中间移动,直到找到符合条件的指针对。
代码
两重遍历法:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ret;
for (int i = 0; i < nums.size(); i++)
{
for (int j = i + 1; j < nums.size(); j++)
{
if (nums[i] + nums[j] == target)
{
ret.push_back(i);
ret.push_back(j);
return ret;
}
}
}
return ret;
}
倒排索引法:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ret;
map<int, int> numsMap;
for (int i = 0; i < nums.size(); i++)
{
if (numsMap.find(target - nums[i]) == numsMap.end())
{
numsMap[nums[i]] = i;
}
else
{
ret.push_back(numsMap[target - nums[i]]);
ret.push_back(i);
break;
}
}
return ret;
}
首尾夹逼法:
struct Compare
{
bool operator() (const pair<int, int> &lhs, const pair<int, int> &rhs)
{
return lhs.second < rhs.second;
}
};
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ret;
vector<pair<int, int>> numsPair;
for (int i = 0; i < nums.size(); i++)
{
numsPair.push_back({i, nums[i]});
}
sort(numsPair.begin(), numsPair.end(), Compare());
int beg = 0;
int end = nums.size() - 1;
while(beg < end)
{
int sum = numsPair[beg].second + numsPair[end].second;
if (sum == target)
{
ret.push_back(numsPair[beg].first);
ret.push_back(numsPair[end].first);
break;
}
else if (sum < target)
{
beg++;
}
else if (sum > target)
{
end--;
}
}
return ret;
}
复杂度再分析
网上看到很多网友说倒排索引法的时间复杂度是O(n),我觉得是不对的,应该是O(nlogn)。假设当前进行到第i次循环,numsMap中有i-1个元素,STL map的find操作是O(logn)的复杂度,那么整个循环的复杂度应该是log1 + log2 + log3 + … + log(i-1) >= (i - 1)log(i-1)。
至于首尾夹逼法,由于有排序,所以复杂度也是O(nlogn)。
总结
当需要用value来定位key的时候,需要用倒排索引;
有序序列可以用二分法、首尾指针夹逼法快速查找元素。