zoukankan      html  css  js  c++  java
  • JS leetcode 两数之和解答思路分析

    壹 ❀ 引

    在学习算法基础的同时,我还是继续捡起leetcode的算法题了,珍惜时间,算法每天进步一点点。不得不说,在了解了一些算法概念后,至少有些答案是能看懂了......(惭愧)虽然我很菜,但是多写多练应该还是会有提升。那么这篇文章就从两数之和开始。

    原题如下:

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个整数,并返回他们的数组下标。

    你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。

    示例:

    给定 nums = [2, 7, 11, 15], target = 9
    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]

    请实现如下方法能达到上述效果:

    /**
     * @param {number[]} nums
     * @param {number} target
     * @return {number[]}
     */
    var twoSum = function(nums, target) {
    
    };
    

    贰 ❀ 听风是风不太聪明的实现

    在解释优质答案前,我先说说自己的思路,毕竟不是很好的做法,大家也可以跳过不看。

    我想出了两种做法,先说第一种,由于只有一个数组,但是我们得让数组中的元素两两相加并与目标值判断是否相等,所以首先想到就是利用for循环嵌套,遍历同一个数组。

    由于不能重复使用同一个元素,所以外层从0开始遍历时,内层循环的索引起点肯定得是1,当外层是1时,内层索引从2开始。这样做的目的除了避免同一元素多次使用外,还减少了重复比较次数。我们来大致脑补下,比如外层是0时,会与内层1相加,而如果内层不在外层基础上加1,就还会出现外层是1时,与内层是0相加比较的情况,这样就重复了。

    所以知道了这些就好做了,直接贴我的实现:

    /**
     * @param {number[]} nums
     * @param {number} target
     * @return {number[]}
     */
    var twoSum = function (nums, target) {
        // 用来装目标索引的空数组
        var result = [],
            len = nums.length;
        for (var i = 0; i < len; i++) {
            // 注意,这里从i+1开始遍历
            for (var j = i + 1; j < len; j++) {
                if (nums[i] + nums[j] === target) {
                    // 注意,concat返回一个新数组
                    result = result.concat(i, j);
                    return result;
                };
            };
        }
    };
    

    我想到的第二种解决思路其实是在学插入排序时得到的灵感,上面的实现简单粗暴,无非就是把一个数组当两个用,第二种思路就是对同一个数组正序倒序同时遍历比较,当然也得使用循环嵌套。

    比如外层循环从0开始,那么内层循环从length-1处倒序遍历,一直遍历到0前面一位,期间的元素分别与0的数字相加并与target比较:

    直接贴我的第二种思路,由于还是使用了循环嵌套,所以耗时相比第一种也只是提升了一点点,但内存使用却大了不少,所以也不算很好的实现。

    /**
     * @param {number[]} nums
     * @param {number} target
     * @return {number[]}
     */
    var twoSum = function (nums, target) {
        var result = [],
            len = nums.length;
        for (var i = 0; i < len; i++) {
            var len_ = len - 1;
            // 倒序遍历,一直遍历到i的前一位
            while (len_ > i) {
                if (nums[i] + nums[len_] === target) {
                    result = result.concat(i, len_);
                    return result;
                };
                len_--;
            };
        };
    };
    

    叁 ❀ 优质解答

    那么在说完我的弱智算法,来看看官方的优质解答,直接贴代码,我们再分析实现:

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

    这个思路其实就是借助了哈希表,牺牲少量空间大大减少运行用时,毕竟只用了一次遍历。如果大家对于哈希表很陌生,还是很推荐大家先理解常用数据结构,我在从零开始的算法入门科普(二)一文中有通过图解简单科普哈希表的概念,只是在上述代码在哈希表存值时并未借助哈希函数。

    通常来说哈希表常常用来存储key-value的数据,由于我们最终是要获取目标元素索引,所以代码实现中直接使用数组元素作为位置映射,用于存储当前元素索引。其次,巧妙通过var dif = target - nums[i]分别获取目标值与当前遍历元素的差值,如果这个差值作为哈希表的索引能访问到有效元素,那么说明当前遍历的i与temp[dif](拿到的是元素在nums中的索引)就是要找的索引。

    不看答案我是真的想不上去,表示惊呆了,那么关于两数之和就说到这了,收获很大!!!

    本文结束!

    2020.5.24复习,与哈希表思路相同,不过这次换成了字典,执行时间会略微提升,代码如下:

    /**
     * @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], i];
            };
            dict[nums[i]] = i;
        };
    };
    
  • 相关阅读:
    水库采样算法
    在Windows的控制台和Linux的终端中显示加载进度
    如何在普通用户权限cmd怎么使用命令行变为管理员权限
    MySql命令行无法显示中文
    MySql精简
    C语言中的数据类型转换函数
    关于C语言命令行参数问题
    postgres 基本操作
    简单的实现HTTP密码验证登陆
    filebeat+logstash配置
  • 原文地址:https://www.cnblogs.com/echolun/p/12877981.html
Copyright © 2011-2022 走看看