Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
每日刷题第67天 2021.03.18
1. 两数之和
- leetcode原题链接:leetcode-cn.com/problems/tw…
- 难度:简单
- 方法:自定义排序+二分查找 or 双指针
题目描述
- 给定一个整数数组 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 <= 10^4-10^9 <= nums[i] <= 10^9-10^9 <= target <= 10^9- 只会存在一个有效答案
思路分析
- 两数之和,最开始的操作
思路的转变
- 可以使用二分查找
or双指针 - 双指针的时间复杂度:
o(n);二分查找的时间复杂度O(nlogn) - 求数组两数之和问题,想到使用左右指针,前提是有序的数组。但是由于题目要求返回的是原数组的索引,因此需要额外申请一个数组副本。
- 1.申请数组副本,并进行升序排序,可直接使用快速排序库函数。
- 2.对副本数组,使用左右指针,初始值左指针为
0,右指针为数组末尾。 - 3.比较两数之和与
target,如果小于target,那左指针往前移动;如果大于target,那么右指针往后移动。 - 4.如果相等,那么需要根据副本数组中的两个值,寻找在原数组中的索引,这里要特别注意,这两个值可能是相等的,需要找到不同的两个索引值。
map
- 解题过程:
- 首先:用
map来存放{数组元素值,坐标}这样的键值对 - 然后运用逆向解法,即用
target减去数组中的某个元素,然后来判断map中是否有相同的值,若有则存在满足条件的答案,返回两个坐标即可;若没有,则保存{数组中某个元素值,对应的坐标}到map对象中。依次遍历即可判断是否有满足条件的两个元素。
AC代码
var twoSum = function(nums, target) {
// 转变思路,选择nums[i] + nums[j] == target 就等价于 target - nums[i] = nums[j]
// 那么就只需要在有序数组中查找符合要求的nums[j]即可
// 二分查找
// 时间复杂度o(nlogn)
const len = nums.length;
let ans = [];
let index = [];
for(let i = 0; i < len ; i++) {
index[i] = i;
}
// 自定义排序
index.sort((a, b) => {
return nums[a] - nums[b];
});
nums.sort((a, b) => {
return a - b;
});
// console.log(index);
function binarySearch(cur){
// console.log('cur',cur)
let l = -1,r = len;
while(l + 1 != r) {
// console.log('l:', l,'r:', r)
let mid = parseInt((l + r) / 2);
// console.log('mid',mid,nums[mid])
if(nums[mid] <= cur){
l = mid;
}else {
r = mid;
}
}
return l;
}
for(let i = 0; i < len; i++) {
let tempt = target - nums[i];
// console.log(tempt,'num:',nums[i])
const targetIndex = binarySearch(tempt);
// console.log(targetIndex)
if(targetIndex != -1 && nums[targetIndex] == tempt){
return [index[i], index[targetIndex]];
}
}
};
总结
- 双指针的做法非常精妙,不要畏惧双指针,其就是相当于数组中的两个下标