1. 两数之和
力扣刷题的第一题,自从我知道有力扣这个刷题平台,这个题应该刷了好多遍了,刚才特意去看了一下提交记录,这两年提交了28次,但是今天再次提交还是做错!这个看题解看视频讲解都看过,所有的感觉都是看过视频或者题解觉得很简单,但是过一段时间重新写还是思路不清晰,写不对!
先说这一次因为有两种写法我之前经常练习,特别是哈希表或者对象存贮需要的值这个方法一印象很深知道大概思路,但是自己开始写代码还是不敢写,所以这次写解法没有用它,而是我自己想到了另外一个非暴力循环的解法,第一次写的时候还是错了,通过调试发现错的并不是离谱,至少思路是对的只不过在最后判断需要值的时候忘记了如果坐标为0,判断也是不成立的具体见下面方法二
先说时间复杂度低的,之循环一次的
思路一 哈希表记录法
思路借鉴官方就是
创建一个哈希表,对于每一个
x,我们首先查询哈希表中是否存在target - x,然后将x插入到哈希表中,即可保证不会让x和自己匹配。
这里需要记录数组的值和下标,前端实际上不用哈希表记录,用对象记录也是一样,所以js想到就是用map和对象来记录.
方法1.1 map (推荐,我觉得这种好理解)
var twoSum = function(nums, target) {
const map = new Map();
for( let i = 0; i < nums.length; i ++ ) {
// 首先就是查看map中是否有 当前值nums[i]相加能够等于target的值 target - num[i]
// 能够找到 就返回
if( map.has(target - nums[i])) {
return [i, map.get(target - nums[i])]
}
// 没有的话就把 当前值储存起来 这里把数组下标index 储存为value的值 方便查找直接返回
map.set(nums[i], i);
}
};
方法1.2 对象
方法二是用对象来储存,其实思路和方法一是一样的,只不过这里查找的是当前值,储存的是当前值nums[i]相加能够等于target的值 target - nums[i],我之前听课最先听到的是这个版本,所以这版本写得多,但是我是觉得这样不好理解,还是推荐方法1.1,这里做参考
var twoSum = function(nums, target) {
const obj = {};
for(let i = 0; i < nums.length; i ++) {
const num = nums[i];
if(num in obj) {
return [i, obj[num]];
}
obj[target - num] = i;
}
};
总结上面两个方法都是基于哈希表储存值的思想,只不过储存方法不一样,其实用对象和用map是可以相互转变的.
时间复杂度:O(n)O(n)
空间复杂度:O(n)O(n)
思路二 暴力双循环,非暴力一个半循环
这个应该是大多说人最先能想到的,思路简单,方法暴力解法,通过双循环遍历数组,找nums[i] + nums[j] === target。具体实现我搜集了两张for循环解法,具体见下面方法2.11和2.12为了看这两个方法的具体运行我直接贴图了
方法2.11
方法2.12
方法2.21
这个方法就是我这次自己想起来的,估计是结合了思路一和思路二想到了一个折中的方法,就是使用一个for循环,然后用和(target)减去每一个遍历值,得到的差值是否在数组中存在,如果存在就取当前两个的下标值。
我最开始的代码也没有简化就是如下,最后直击败了5%的用户,于是我改造一下在运行,也直接贴图了
var twoSum = function(nums, target) {
for( let i = 0; i < nums.length; i ++) {
const num = nums[i];
const otherNum = target - num;
const inx = nums.findIndex(item => item === otherNum);
console.log(otherNum, inx)
if (inx >= 0 && inx !== i) {
return [inx, i]
}
}
};
改造后的代码如下
方法2.22
总结这个方法和方法2.21其实就是查找元素所在数组下标的方法不一样,但就这,最后测试结果发现这个方法明显优于2.21
- 时间复杂度:O(N^2),其中 N 是数组中的元素数量。最坏情况下数组中任意两个数都要被匹配一次。
- 空间复杂度:O(1)。