JS leetcode 两数之和 II - 输入有序数组 题解分析


风晓
风晓 2024-01-03 01:08:33 51388 赞同 0 反对 0
分类: 资源
JS leetcode 两数之和 II - 输入有序数组 题解分析

 

壹 ❀ 引

我在JS leetcode 两数之和 解答思路分析一文中首次解决两数之和等于目标值的问题,那么今天遇到的是两数之和的升级版,题目为leetcode167. 两数之和 II - 输入有序数组,题目描述如下:

给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。

函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。

说明:

返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:

输入: numbers = [2, 7, 11, 15], target = 9
输出: [1,2]
解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

我们还是先分析题目,给出我的想法,再看看优质的解题思路。

贰 ❀ 解题思路

其实相比先前第一次遇到的两数之和,题目变化只有两处:

第一,数组这次变成了有序数组,数组元素排序为由小到大;

第二,这次返回的下标值不是从0开始,而是从1开始,且index1 必须小于 index2。

由于在上次的解答中,我们已经提出了可以使用哈希表的做法,只用一次遍历即可解决问题,但后来博客园用户MrSmileZhu留言说使用字典会比哈希略快,所以这里我贴字典的做法,实现思路与哈希表相同:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
    var i = 0,
        len = nums.length,
        dict = {};
    for (; i < len; i++) {
        var dif = target - nums[i];
        if (dif in dict) {
            return [dict[dif] + 1, i + 1];
        };
        dict[nums[i]] = i;
    };
    return [];
};

思路这里再简单复述,比如目标值是9,第一次遍历差值为9-2=7,我们创建一个空对象,很明显这时候不可能从空对象里找到key为7的属性,所以我们把当前遍历元素作为key,索引作为value存进去,此时对象变成了:

dict = {
    2:0
};

OK,第二次遍历,差值为9-7=2,哎,我们成功的再dict中找到了key为2的属性,所以上一次遍历的元素与当前元素的和刚好等于9,所以我们只用拿到dict[2]与数组当前遍历的 i 即可,由于这次下标是从1开始,所以最终返回dict[2] + 1, i + 1

值得注意的是,这道题出现在数组和字符串卡片的双指针技巧中,所以出题人本意是希望我们用双指针来解决这个问题的,关于双指针我们在JS leetcode 反转字符串 题解分析第一次遇到,说到底就是定义两个变量i与j,一个正向递增一个反向递减同时遍历。

而且我在两数之和的第一篇博客中,我的第二种思路也类似双指针的想法,我的思路其实是,一开始让i为0,j能一直递减遍历到i的后一位,中途一直相加与目标值比较,如果不满足,让i自增一位,j再次从尾部开始倒序遍历,再次相加对比。

但是这样我就又不得不使用两次遍历嵌套...外层遍历控制i,内层遍历控制j递减,想了很久也没好的办法。

无奈之下看了其他用户的思路,瞬间顿悟了....先贴代码,原理其实很简单,这里参考了leetcode用户CyC2018的实现思路:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
    var i = 0,
        j = nums.length - 1;
    while (i < j) {
        if (numbers[i] + numbers[j] === target) {
            return [i + 1, j + 1]
            // 如果两数之和比目标值小,让i往右移
        } else if (numbers[i] + numbers[j] < target) {
            i++
            // 如果两数之和比目标值大,让j往左移
        } else {
            j--
        };
    };
    return [];
};

看了代码中的两句注释,其实大家应该也明白了,一开始我们就选中了数组的第一位与最后一位元素,相加并与目标值比较,关键线索数组是从小到大排列的有序数组,所以如果第一次比较就比目标值大,我们就让j往左移动,这样两数之和会变小,再次与目标值比较。

如果这次小了,我们再让i往右移,这样两数之和会变大,所以通过这种思路,我们依赖if (numbers[i] + numbers[j] === target)这行代码,试探性的让 i 与 j 变化,直到找到目标索引,再分别加1即可。

OK,关于两数之和的升级版就说到这了。

如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!

评价 0 条
风晓L1
粉丝 1 资源 2038 + 关注 私信
最近热门资源
银河麒麟桌面操作系统备份用户数据  129
统信桌面专业版【全盘安装UOS系统】介绍  128
银河麒麟桌面操作系统安装佳能打印机驱动方法  119
银河麒麟桌面操作系统 V10-SP1用户密码修改  108
麒麟系统连接打印机常见问题及解决方法  20
最近下载排行榜
银河麒麟桌面操作系统备份用户数据 0
统信桌面专业版【全盘安装UOS系统】介绍 0
银河麒麟桌面操作系统安装佳能打印机驱动方法 0
银河麒麟桌面操作系统 V10-SP1用户密码修改 0
麒麟系统连接打印机常见问题及解决方法 0
作者收入月榜
1

prtyaa 收益393.62元

2

zlj141319 收益218元

3

1843880570 收益214.2元

4

IT-feng 收益210.13元

5

风晓 收益208.24元

6

777 收益172.71元

7

Fhawking 收益106.6元

8

信创来了 收益105.84元

9

克里斯蒂亚诺诺 收益91.08元

10

技术-小陈 收益79.5元

请使用微信扫码

加入交流群

请使用微信扫一扫!