算法题-JS实现求两数之和
- [ ]两数之和
- leetcode原题链接
学习内容:
给定一个整数数组 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]
解题思路:
方法一.可以通过排序+双指针的解法实现
首先对数组进行排序,之后设置左右两个指针分别指向有序数组的第一个元素与最后一个元素,当左指针指向的元素位于右指针左侧时,将两个指针指向的元素相加,再与target进行比较,会出现以下三种情况:
- 如果两数之和等于target,则此时左右指针指向的元素就是题目中需要求得的元素,返回两个元素在原数组下标即可
- 如果两数之和大于target,因为是有序数组,因此将右指针左移才能让两数之和减小(左指针右移只会让两数之和变得更大,更偏离target)
- 如果两数之和小于target,则将左指针右移
解题代码如下:
var twoSum = function (nums, target) {
// 这里先定义一个全新数组,因为需要保留原数组用于判断后续得出的结果在原数组中的数组下标
let arr = JSON.parse(JSON.stringify(nums))
arr.sort((a, b) => a - b)
let length = nums.length;
let result = []
for (let i = 0; i < length - 1; i++) {
// 定义左、右两个指针的位置
let left = i;
let right = length - 1;
let sum;
while (left < right) {
// 当左指针在右指针左侧时,判断此时左指针指向的元素与右指针指向元素的和与target进行比较
sum = arr[right] + arr[left]
// 相同时,将当前左右指针在原数组中的数组下标推入最终返回结果
if (sum === target) {
// 左指针与右指针指向的元素不相等时,直接推入即可
if (arr[left] !== arr[right]) {
result.push(nums.indexOf(arr[left]), nums.indexOf(arr[right]))
return result
} else {
// 左右指针指向的元素相等时,需要进行判断,得出元素在原数组中的不同位置,又因为两个数相同,因此通过target/2即可得到此时的数
result.push(nums.indexOf(arr[left]), fn(nums, target / 2))
return result
}
} else if (sum > target) {
// 如果两数相加大于target,则右指针左移
right--
} else {
// 否则,左指针右移
left++
}
}
}
return result
}
// 返回得到元素在原数组中的第二个下标位置
const fn = (arr, val) => {
// 首先将相同数字在数组中删除
arr.splice(arr.indexOf(val), 1)
// 计算此时该元素在被删除第一个元素后的数组中的index,然后加上被删除的那个元素的位置(即得出的index+1),即可得到该元素在原数组中的第二个位置,然后返回
return arr.indexOf(val) + 1
}
方法二.可以通过判断target与元素之间的差值是否在原数组中出现过
对数组进行遍历,判断target与当前元素的差值是否在原数组中出现过,如果出现过,则当前元素的下标与差的下标就是题目中需要的数组下标
var twoSum = function (nums, target) {
let difference;
let result = [];
let length = nums.length;
for (let i = 0; i < length - 1; i++) {
difference = target - nums[i];
// 判断差值是否在原数组中出现
// 如果在原数组中出现过,还需要判断当差值与此时判断的元素相同时,差值是否就是当前元素,如果就是当前元素,则此次返回的结果无效,因为题目明确写了【数组中同一个元素在答案里不能重复出现】
if (nums.indexOf(difference) !== -1 && (nums.indexOf(difference) !== i || countOccurrences(nums, difference))) {
let arr = JSON.parse(JSON.stringify(nums))
// 判断差值是否与当前元素是否相同
if (difference !== arr[i]) {
// 如果不同,直接推入当前元素与差值的下标即可
result.push(i, nums.indexOf(difference))
return result
} else {
// 两数相同时,需要向结果中推入当前元素在原数组中的下标与差值的下标(不同于当前元素的下标)
result.push(i, fn(arr, target/2))
return result
}
}
}
return result
}
// 判断元素是否在数组中出现多次
function countOccurrences(arr, num) {
return arr.filter(function (element) {
return element === num;
}).length > 1;
}