# 1.Two Sum
题目
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].
给定一个整数数组nums和一个整数target,在数组中查找两个数使得两数之和等于target,最终返回这两个数在数组中的下标。
我们可以设定每个输入都有一个解,同一个数字不能用两次。
例子中,2+7=9,所以返回的数组为[0,1].
解
最简单
最容易想到的方法是数组遍历,使用两层循环,找到target的解。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
if (nums.empty()) return {};
for (int i=0; i< nums.size(); i++){
for (int j=i+1; j< nums.size(); j++){
if (nums[i] + nums[j] == target)
return {i, j};
}
}
return {};
}
};
这种方法虽然简单,但是耗时比较长。时间复杂度为O(N^2).
方法二 map
算法中一个常见的降低耗时的方法是空间换时间。应用在这里就是说,我们将数组存储在一个可以直接查找数值的数据结构中,这个数据结构存储数值和对应下标,这种数据结构可以称为字典。键是数值,值是下标。
这里没有必要先将所有的数值都存储在数据结构中,可以一边遍历数组,一遍进行数值存储(数据结构的赋值)。
CPP中我们可以使用map容器进行数值存储。代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int, int> dict;
for (int i=0; i< nums.size(); i++){
if (dict.find(target-nums[i]) != dict.end())
return {dict[target-nums[i]], i};
dict[nums[i]] = i;
}
return {};
}
};
CPP中除了可以使用map容器外,还可以使用unordered_map容器,代码如下:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> dict;
for (int i=0; i< nums.size(); i++){
if (dict.find(target-nums[i]) != dict.end())
return {dict[target-nums[i]], i};
dict[nums[i]] = i;
}
return {};
}
};
两者代码基本上相同,除了数据声明不同。
三种方法耗时,内存占用情况如下。
image-20200403221647958.png可以看到,方法二相较于方法一的两层循环在耗时上优化很大,但是代价是内存占用的增加。此外,unordered_map与map相比耗时更少,但内存占用是最多的。
小结
- 时间换空间,空间换时间。两者是一个比较矛盾的方面,如果方法耗时较长,我们可以想办法将部分结果存储起来,可能会减少耗时。
- map和unordered_map两者底层实现的数据结构不同。map插入元素之间是有顺序的,unordered_map元素之间没有顺序;map底层实现基于AVL树,当元素插入导致树不再平衡时,需要进行调整;unordered_map底层基于hash实现,因此查找、插入和删除速度比较快。
网友评论