题目描述(简单题)
我们的目标是:给定确定数组和一个目标和,在数组中找两个数字相加等于目标和的项目,输出这两个数字的下标。
解法一 双重循环
本解法倾向于暴力解法,并且比较耗费空间,因为添加了一个多余的vector作为中间存储区。
时间复杂度:因为是两层 for 循环, O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
C++ 解法:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target)
{
vector<int> result;
for(int i=0;i<nums.size();i++)
{
int tmp=target-nums[i];
for(int j=i+1;j<nums.size();j++)
{
if(nums[j]==tmp)
{
result.push_back(j);
result.push_back(i);
}
}
}
return result;
}
};
Golang解法:
func twoSum(nums []int, target int) []int {
for i:=0;i<len(nums);i++{
for j:=i+1;j<len(nums);j++{
if nums[i]+nums[j]==target{
return []int{i,j}
}
}
}
return []int{}
}
解法二 利用哈希表
在上边的解法中,我们可以观察下第二个 for 循环步骤。
for j:=i+1;j<len(nums);j++{
if nums[i]+nums[j]==target{
那么,我们如果换一种理解方式和思路,可以得到下面的结论:
for j:=i+1;j<len(nums);j++{
sub = target - nums[i]
if nums[j]==target{
第二层 for 循环无非是遍历所有的元素,看哪个元素等于 sub ,时间复杂度为 O ( n ) O(n) O(n)。
那么,有没有一种方法,不用遍历就可以找到元素里有没有等于 sub 的?
hash table !!!!
我们可以使用哈希表来解决这个问题。
我们可以把数组的每个元素保存为 hash 的 key,下标保存为 hash 的 value 。
这样仅剩下需判断 sub 在不在 hash 的 key 里就可以了,而此时的时间复杂度仅为 O ( 1 ) O(1) O(1)!
需要注意的地方是,还需判断找到的元素不是当前元素,因为题目里讲一个元素只能用一次。
时间复杂度:比解法一少了一个 for 循环,降为 O ( n ) O(n) O(n)。
空间复杂度:所谓的空间换时间,这里就能体现出来, 开辟了一个 hash table ,空间复杂度变为 O ( n ) O(n) O(n)。
C++解法:
class Solution
{
public:
vector<int> twoSum(vector<int> &nums, int target)
{
//Key是数字,value是该数字的index
unordered_map<int, int> hash;
vector<int> result;
int numsSize = int(nums.size());
for (int i = 0; i < numsSize; i++)
{
int numberToFind = target - nums[i];
//如果找到numberToFind,就return
if (hash.find(numberToFind) != hash.end())
{
result.push_back(hash[numberToFind]);
result.push_back(i);
return result;
}
//如果没有找到,把该数字的index放到hash表中
hash[nums[i]] = i;
}
return result;
}
};
Golang解法:
func twoSum(nums []int, target int) []int {
num_map := make(map[int]int)
result_list := make([]int, 2)
for index_value, first_num := range nums {
second_value := target - first_num
if second_index, ok := num_map[second_value]; ok {
result_list[0] = second_index
result_list[1] = index_value
return result_list
}
num_map[first_num]=index_value
}
return result_list
}
解法三 合并循环的方式
看解法二中,两个 for 循环,他们长的一样,我们当然可以把它合起来。复杂度上不会带来什么变化,变化仅仅是不需要判断是不是当前元素了,因为当前元素还没有添加进 hash 里。
C++解法:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int, int> index_map;
vector<int> ans;
for (int i = 0; i < nums.size(); ++i) {
if (index_map.count(nums[i])) {
ans.push_back(index_map[nums[i]]);
ans.push_back(i);
return ans;
}
index_map[target - nums[i]] = i;
}
return ans;
}
};
Golang解法:
func twoSum(nums []int, target int) []int {
num_map := make(map[int]int)
result_list := make([]int, 2)
for index_value, first_num := range nums {
second_value := target - first_num
if second_index, ok := num_map[second_value]; ok {
result_list[0] = second_index
result_list[1] = index_value
return result_list
}
num_map[first_num]=index_value
}
return result_list
}
参考链接声明
关于Java的解法可以主要品读上述的文章。
成长,就是一个不动声色的过程,一个人熬过一些苦,才能无所不能。