问题:
- 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个整数,并返回它们的数组下标。
- 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
- 你可以按任意顺序返回答案
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
来源:力扣(LeetCode)
初级受挫:
最初的思路是,target中的元素应该是少于nums的,所以先从target下手,寻找nums中小于target某一元素的子集,然后在子集中再继续计算结果。
寻找子集的过程想到的是for循环遍历target然后for循环遍历nums,子集的元素加入到unorderedset中。
在子集中寻找符合条件的元素组合暂时没有好的思路,应该是动态优化问题吧,遍历太麻烦了,我想到的是不断遍历累加,如果得到的值已经大于了target_element就没必要再继续算了,重新开始组合。但是如何重新组合呢?比如target元素为7,现在是1+3,再+5越界,这时应该是越过5找其他合适的。目前我想到的方法是通过一个键值对保存原来数组的索引的取值(应该是用unorderedmap实现吧),然后对进入子集的键值对再按照value排序(如何实现呢???),排序后只需要子集的首部开始累加就可以了,如果等于target_element就返回两个键值对的索引(如何实现呢???),如果大于target_element则跳出本次累加过程对下一个target_element进行累加。
#include<unordered_set>
#include<algorithm>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int numsSize(nums.size());
int sum2(0);
unordered_set<int> s;
for (int x: target){
for (int i=0; i<numsSize; i++){
if (nums[i]<target && s.find(nums[i]) != s.end())
s.insert(nums[i]);
}
sort(s.begin(),s.end());
for (int y : s){
sum2+=y;
if (sum2 == r)
}
}
}
};
成功尝试:
上述思考失败后,不肯轻易放弃的我又想了一个简单的思路:
根据两数的限定条件,查找target_element - nums[i],并成功通过,总结经验如下:
- 看清楚需求,输入的类型什么,返回类型是什么,然后再对症下药
- 对输入数据的情况进行分析,常有0,负数,负正,正正,相同这几种情况,都不要疏漏。
- return 的result直接用{j,k}表示!
#include<unordered_set>
#include<algorithm>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int numsSize(nums.size());
int sum2(0);
vector<int> result(2);
for (int j=0; j<numsSize-1; j++){
//if (nums[j]<=target){//考虑到0的情况应该是<=而非=
sum2 = target - nums[j];
for (int k=j+1; k<numsSize; k++){
//if (nums[k]<=target){//含有负数时不再适用,如[-3,3],0
if (nums[k]== sum2){
result[0]=j;
result[1]=k;
return result;
}
//}
}
//}
}
return result;
}
};
哈希表的优化解法:
综合上述的两个思考:
- 认为unodered_map应该是基础
- 核心思想为查找target_element - nums[i]
解:
#include<unordered_map>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,int> map;
for(int i=0;i<nums.size();++i){
/*if (map.find(target-nums[i]) != map.end())
return {i,} 无指针无法返回值!!!
*/
unordered_map<int,int>::iterator it = map.find(target-nums[i]);
//auto it = map.find(target-nums[i]);
if (it != map.end())
return {it->second,i};//value
map[nums[i]]=i;//key-value
}
return {};
}
};
忘记分号,for循环忘记声明i的类型这种小问题不应该犯!!!
此外,注意unordered_map的使用:
- find() 用于找key,然后配合iterator来指向first 或 second
- 可以考虑auto指针 unordered_map<int,int>::iterator it = map.find(target-nums[i]); //auto it = map.find(target-nums[i]);
- 注意for循环中一个常用的逻辑,和我们的常规思维不太一样的是,这里是一直if判断是否在(与本次循环有关的值),不在的话就加入本次循环的值,开启下一次循环。这样的时间复杂度就变成了O(n)!
再优化:
#include<unordered_map>
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int length = nums.size();
unordered_map<int, int> numMap;
for (int index = 0; index < length; index++) {
if ( numMap.find(target - nums[index]) != numMap.end() ) {
return {numMap[target - nums[index]], index};
}
numMap[nums[index]]=index;
}
return {};
}
};