题目
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
题目解析及优化
-
暴力解决法
暴力解决法很好理解,逐步遍历所有的数组组合,找出答案。由于时间复杂度很高,就不贴代码了,太弟弟了。
-
排序+双指针法
先将数组排好序,用两个指针分别指向开始结尾,开始往中间聚拢。如果两指针碰头,就说明没有找到答案。
代码如下:
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { //ans存储答案的两个数 vector<int> ans; //temp存储排序之后的数组, //由于之后需要原数组的位置,不能对原数组直接排序 vector<int> temp; temp=nums; int n=temp.size(); //sort排序的方法推荐读者掌握,很多时候都可以用到 sort(temp.begin(),temp.end()); //两个下标指向开始和结尾 int i=0,j=n-1; while(i<j) if(temp[i]+temp[j]>target){j--;} else if(temp[i]+temp[j]<target){i++;} else break; } if(i<j){ //如果两指针没有碰头说明有答案存在,与之前的下标对应 for(int k=0;k<n;k++){ if(i<n&&nums[k]==temp[i]){ ans.push_back(k); i=n; } else if(j<n&&nums[k]==temp[j]){ ans.push_back(k); j=n; } if(i==n&&j==n)return ans; } } return ans; } }; -
哈希表
此方法需要哈希表的一些知识,可以点击此处。
我们是在知道和的情况下去找两个加数,那么自然可以用一个加数去找另一个加数,遍历一个数组的元素,如果和减去这个元素的值在另一个数组里面出现过,那么答案存在。这个方法明显比暴力解决法更简洁。
在用哈希表的时候也有两种方法:
- 用两次哈希表:第一次将数组的值和索引添加到表中,第二次遍历寻找每个元素以及target-nums[i],切记,同一个元素不能用两次。
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> ans; map<int,int> p; int l = nums.size(); for(int i = 0;i<l;i++){ //p.second是数字的下标+1,只要存在就不会为0 p[nums[i]] = i+1; } for(int i = 0;i<l;i++){ //用两个判断条件 if(p[target-nums[i]]&&(i!=p[target-nums[i]]-1)){ ans.push_back(i); ans.push_back(p[target-nums[i]]-1); return ans; } } return ans; } };-
用一次哈希表:其实在上述的用两次哈希表的方法中,会有重复计算的部分,在找一个元素的时候,同时已经找了target-nums[i]的元素,两者选其一即可,在将数组添加到表中的时候,就可以直接寻找,不会影响答案,而且比上述方法更省时间。代码如下:
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> ans; map<int,int> p; int l = nums.size(); for(int i = 0;i<l;i++){ if(p[target-nums[i]]){ ans.push_back(i); ans.push_back(p[target-nums[i]]-1); return ans; } //将赋值放在判断之后就能避免判断同一元素的情况 p[nums[i]] = i+1; } return ans; } };提交之后,发现用时更短的人用的是unordered_map,由于底层原理的不同,unordered_map用的是哈希表,查找的时间复杂度为o(1)
心得及总结
- 暴力法并不是一无是处,有时候在需要时间换取空间的时候可以采取暴力法。(少见)
- 除了暴力法以外的几种方法,均采用了元素互补的思想:即两个元素之间有某种关系的时候,可以用一个元素去找另一个元素,而不用专门去找。
- 这个题目中是用一次哈希表时间胜出了,但是如果题目中是有序数组的话,用指针就会更优秀了。
- 在哈希表的使用过程中,并没有用到map的自动有序的特性,所以可以使用unordered_map去更节省时间。(充分利用不同数据结构的优点)
知识补充
-
三种map的优缺点

运行效率方面:unordered_map最高,hash_map其次,而map效率最低单提供了有序的序列。
占用内存方面:hash_map内存占用最低,unordered_map其次(数量少时优于hash_map),而map占用最高。
需要无序容器时候用unordered_map,有序容器时候用map。
本文探讨了在给定数组中寻找两个数使它们的和等于特定目标值的问题。介绍了暴力解法、排序+双指针法及哈希表法等高效算法。并对各种方法进行了对比分析。
410

被折叠的 条评论
为什么被折叠?



