LeetCode js题解 两数之和I/II/IV、三数之和/最接近的三数之和

这篇博客详细解析了LeetCode中的四道经典题目:两数之和I/II/IV及最接近的三数之和。博主通过哈希表、有序数组和二叉搜索树等方法,介绍了如何利用双指针和中序遍历等策略高效求解。并提供了每道题目的题解思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

把两数之和和三数之和的题目都刷了一遍,熟悉一下这类题。

两数之和

题源:https://leetcode-cn.com/problems/two-sum

题解

通过目标数减去当前数,在哈希表中寻找存在的组合,两次遍历可以完成,当然还可以缩减到一次遍历。
这种类似于用哈希表做登记的思路是比较简单也容易想到的,leetcode只要求输出一组结果,所以找到直接return即可。

Code
var twoSum = function(nums, target) {
    if(nums.length<=1) return [];
    let map = new Map();
    for(let i=0;i<nums.length;i++){
        if(map.has(target-nums[i])){
            return [i,map.get(target-nums[i])];
        }
        map.set(nums[i],i);
    }
    return [];
};

两数之和 II- 输入有序数组

题源:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted

题解

哈希的解法是可行的,但为了有效利用输入的有序数组,我们可以用左右指针的做法去搜索(不过可能需要考虑一下两数之和是否有可能溢出)。

Code
// 哈希解法 O(n),O(n)
var twoSum = function(numbers, target) {
    let map=new Map();
    for(let i=0;i<numbers.length;i++){
        let sum=target-numbers[i];
        if(map.has(sum)){
            return [map.get(sum),i+1];
        }
        map.set(numbers[i],i+1);
    }
    return [];
};

// 双指针解法 O(n),O(1)
var twoSum = function(numbers, target) {
    let left=0,right=numbers.length-1;
    while(left<right){
        let sum=numbers[left]+numbers[right];
        while(sum>Number.POSITIVE_INFINITY) --right;// 向上溢出
        while(sum<Number.NEGATIVE_INFINITY) ++left;// 向下溢出
        if(sum==target)
            return [left+1,right+1];
        else if(sum<target){
            ++left;
        }else{
            --right;
        }
    }
    return [];
};

两数之和 IV - 输入 BST

题源:https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst

题解

这道题和剑指offer上的《二叉树上某一路径的和》很相似。被列为简单题,在于只需要证明是否存在两个元素的和等于给定的目标结果即可。由于是BST,使用中序遍历可以得到一个升序的数组,所以预处理一下即可。
或者使用哈希的做法,结合任意的遍历搜索方式,比如说BFS,也可以得到答案。

Code

// 中序遍历+左右指针,相当于两数之和 II
var findTarget = function(root, k) {
    if(!root) return false;
    let nums=[];
    function inOrder(node){
        if(!node)
            return;
        inOrder(node.left);
        nums.push(node.val);
        inOrder(node.right);
    }
    inOrder(root);
    let left=0,right=nums.length-1;
    while(left<right){
        let sum=nums[left]+nums[right];
        while(sum>Number.POSITIVE_INFINITY) --right;
        while(sum<Number.NEGATIVE_INFINITY) ++left;
        if(sum==k)
            return true;
        else if(sum<k){
            ++left;
        }else{
            --right;
        }
    }
    return false;
};

// 哈希表+BFS
var findTarget = function(root, k) {
    let stack=[root];
    let map=new Map();
    while(stack.length){
        let cur=stack.pop();
        if(map.has(k-cur.val))
            return true;
        map.set(cur.val,true);
        if(cur.left) stack.push(cur.left);
        if(cur.right) stack.push(cur.right);
    }
    return false;
};

三数之和

题源:https://leetcode-cn.com/problems/3sum

题解

从两数之和过来,不同的地方在于,这次是一个数,去找和它配对的另外两个数。由于三数之和要求为0,我们可以先确定一个数,假如它是正的,那另外两个数之和肯定为负数,反之同理。
为了方便求解,我们可以先对给定的数组进行升序排序,这样负数都会集中在左侧,正数集中在右侧。假如我们选定第一个数,那么只需要往右再任取两个数进行求和,满足条件即可返回。而怎么取这两个数,其实有技巧可循。

我们知道,经过升序排列后的数组右侧必然是数组中的较大数,而左侧必是较小数,所以我们可以在第一个数的右边与数组的尾部设置左右指针去获取这两个数,并不断与定位的第一个数进行比较,通过左指针或者右指针的移动来调整和的大小,最终找到可行解。

1、如果三数之和为0,那么就找到了一个可行解;
2、如果三数之和小于0,那么左指针应当右移,使得另外两数之和增大;
3、如果三数之和大于0,那么右指针应当左移,使得另外两数之和减小。

三数之和_题解

图片源自
作者:githber
链接:https://leetcode-cn.com/problems/3sum/solution/three-sum-giftu-jie-by-githber/
来源:力扣(LeetCode)

当然还有特殊情况,比如说,第一个数大于0,那么我们其实可以结束搜索,因为之后是再也找不到可行解了;还有右指针所指的数字也是负数,那么说明左指针所指的数字也是负数,这种情况下三个数字之和不可能为0,同理,第一个数大于0的情况也可以归纳到这种情况当中。

为了避免多次取得可行解,我们还要避免多次定位相同的数字,可以通过while循环跳过。

最终代码如下:

Code
var threeSum = function(nums) {
    let res = [];
    nums.sort((a,b)=>a-b);
    let size=nums.length;
    if(nums[0]<=0&&nums[size-1]>=0){
        let i=0;
        while(i<size-2){
            if(nums[i]>0) break;// 最小数大于0,无解
            let left=i+1;
            let right=size-1;
            while(left<right){
                if(nums[i]*nums[right]>0) break;// 三数同号,无解
                let sum=nums[i]+nums[left]+nums[right];
                if(sum===0){
                    res.push([nums[i],nums[left],nums[right]]);
                }
                if(sum<=0){
                    // 和小于0或者已找到一个可行解
                    // 左指针右移
                    while(nums[left]===nums[++left]){}// 跳过重复值
                }else{
                    // 和大于0
                    // 右指针左移
                    while(nums[right]===nums[--right]){}// 跳过重复值
                }
            }
            while(nums[i]===nums[++i]){}
        }
    }
    return res;
}

最接近的三数之和

题源:https://leetcode-cn.com/problems/3sum-closest

题解

使用一个变量记录最接近的值即可,方法上和《三数之和》差不多。

Code
var threeSumClosest = function(nums, target) {
    if(nums.length<=2) return null;
    nums.sort((a,b)=>a-b);
    let ans=nums[0]+nums[1]+nums[2];
    let i=0,size=nums.length;
    while(i<size-2){
        let left=i+1,right=size-1;
        while(left<right){
            let sum=nums[i]+nums[left]+nums[right];
            if(sum===target)
                return target;
            if(Math.abs(sum-target)<Math.abs(ans-target)){
                ans=sum;
            }
            if(sum<=target)
                ++left;
            else
                --right;
        }
        while(nums[i]==nums[++i]){}
    }
    return ans;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值