JavaScript的two-sum问题解法

一个很常见的问题,找出一个数组中和为给定值的两个数的下标。为了简单一般会注明解只有一个之类的。

最容易想到的方法是循环遍历,这里就不说了。

在JS中比较优雅的方式是利用JS的对象作为hash的方式:

 1 var twoSum = function(nums, target) {
 2     var hash = {};
 3     var i;
 4     for (var i = 0; i < nums.length; i++ ) {
 5         if (typeof hash[nums[i]] !== "undefined") {
 6             return [i, hash[nums[i]]];
 7         }
 8         hash[target - nums[i]] = i;
 9     }
10 };

这里面还可以做一些小的优化,比如把length拿出来,重复使用的 nums[i] 也抽取出来,遍历的顺序反过来等,最后大概弄成这个样子:

var twoSum2 = function(nums, target) {
    var hash = {};
    var i;
    var tmp;
    for (i = nums.length; i--; ) {
        tmp = nums[i];
        if (typeof hash[tmp] !== "undefined") {
            return [i, hash[tmp]];
        }
        hash[target - tmp] = i;
    }
};

不过这些小的优化基本上不影响大局,在leetcode上测试了好几遍,排名总在75%到85%之间浮动。居然连90%都没达到,我对你很失望

让我再想想……

哦对了我记得前几天看到过一个优化循环的方法叫做Duff Device来着,不如试试?

链接在这里 https://en.wikipedia.org/wiki/Duff%27s_device。(怎么插入链接来着?)

这东西我的大概理解就是就是把for循环稍微展开一下,本来循环80次的行为,改写成执行10次循环,每次循环里执行8次。这样可以省下一点调用for循环的开销。不过这个前提是for循环里的执行代码比较简单。如果耗时主要在每个循环里的话,这招就不太管用了听说。

于是我照着介绍的例子,把上面的代码改写了一下:

 1 var twoSum1 = function(nums, target) {
 2     var hash = {};
 3     var i = 0;
 4     var startIndex = nums.length % 8;
 5     var iterations = nums.length / 8;
 6     do {
 7
 8         switch(startIndex) {
 9             case 0: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
10             case 7: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
11             case 6: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
12             case 5: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
13             case 4: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
14             case 3: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
15             case 2: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
16             case 1: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
17         }
18
19     } while (--iterations);
20
21 };

嗯,看上去很厉害的样子。接下来在浏览器里测试一下:

先构造一个长度为1000的数组,来来来:

呃……好像没什么差别。把数据加大一点,到100000吧:

卧槽牛逼啊!赶紧把这个放leetCode上试试!

……

……

……

然而在leetCode上试了之后,虽然通过了,发现和之前的执行效率并没有多大差别……依然没有到90%

一定是leetCode上的单测数据太小了!于是自个儿在leetCode上的那个小输入框里粘贴了一个十几万长度的数据,跑了一遍,发现仍然没有什么卵用。

所以大概是我的测试方法有问题?数据翻了100倍时间居然并没有增加多少,好奇怪。

好吧,这个方法就暂时搁着。再想想其它歪主意。

用js自带的forEach做循环试试吧,说不定会比手写的要快点。于是有了下列代码:

var twoSum = function (nums, target) {
    var hash = {};
    var result = [];
    nums.forEach(function (v, i) {
        if (typeof hash[v] !== "undefined") {
            result[0] = i;
            result[1] = hash[v];
        }
        hash[target - v] = i;
    });
    return result;
}

不过这有个问题是,forEach循环没法正常地退出,所以无论怎样都要遍历一下整个数组,不能像前面那样找到正确的就退出了,感觉太好。

所以只能让它不正常地退出了:

var twoSum = function (nums, target) {
    var hash = {};
    var result = [];
    try {
      nums.forEach(function (v, i) {
          if (typeof hash[v] !== "undefined") {
              result[0] = i;
              result[1] = hash[v];
              throw "err";
          }
          hash[target - v] = i;
      });
    } catch (err) {
        return result;
    }
}

好的就这样,跑一下试试:

噢好吧,好歹过了90%……

想到更快的方法再更………………

  

时间: 2024-10-29 20:17:05

JavaScript的two-sum问题解法的相关文章

JavaScript中大数相加的解法

一.两个大正整数字符串相加 在JavaScript中,数值类型满足不了大数据容量计算,可以用字符串进行操作 1 function add(strNum1, strNum2) { 2 // 将传进来的数字/数字字符串调用toString方法转换成字符串,并进行切割,专成数组 3 let splitNum1 = strNum1.toString().split(''), 4 splitNum2 = strNum2.toString().split('') 5 6 // 判断两个数组的长度,进行值的互

Max double slice sum 的解法

1. 上题目: Task description A non-empty zero-indexed array A consisting of N integers is given. A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice. The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... +

leetcode笔记:Combination Sum II

一. 题目描述 Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C once number of times. Note: ? All numbers (including target)

JavaScript函数调用

一.第一种情况:在<script></script>标签内调用. 1 <script type="text/javascript"> 2 function add() 3 { 4 sum = 1 + 2; 5 alert(sum); 6 } 7 add();//调用函数,直接写函数名. 8 </script> 9 10 另一种写法 11 <script type="text/javascript"> 12

javascript 基础语法

1. 变量 从字面上看,变量是可变的量:从编程角度讲,变量是用于存储某种/某些数值的存储器.我们可以把变量看做一个盒子,盒子用来存放物品,物品可以是衣服.玩具.水果...等. 1.1 变量命名规则 1.1.1.必须以字母.下划线或美元符号开头,后面可以跟字母.下划线.美元符号和数字. 1.1.2.变量名区分大小写,如:A与a是两个不同变量. 1.1.3.不允许使用JavaScript关键字和保留字做变量名. 1.2 变量声明 声明变量语法: var 变量名, 如 var mynum :声明多个变

javascript 函数(2)

一.什么是函数 函数的作用,可以写一次代码,然后反复地重用这个代码. 比如:我们要完成多组数和的功能. var sum; sum = 3+2; alert(sum); sum=7+8; alert(sum); .......     //不停地重复这两行代码 使用函数,可以大大降低工作量: function add2(a,b){   sum= a + b;   alert(sum); }  //只需写一次 add2(3,2);      // 实现3+2   等于是  sum=3 + 2和ale

Javascript学习三

//imooc.com js 给变量取个名字(变量命名) 我们为了区分盒子,可以用BOX1,BOX2等名称代表不同盒子,BOX1就是盒子的名字(也就是变量的名字). 我们赶快给变量取个好名字吧!变量名字可以任意取,只不过取名字要遵循一些规则: 1.必须以字母.下划线或美元符号开头,后面可以跟字母.下划线.美元符号和数字.如下: 正确: mysum _mychar $numa1 错误: 6num //开头不能用数字 %sum //开头不能用除(_ $)外特殊符号,如(% + /等) sum+num

JavaScript进阶(四)

现在说说什么是函数.函数的作用可以写一次代码,然后反复的重用这个代码.如:我们要完成多组数和的功能.var sum;sum=3+2;alert(sum); sum=7+8;alert(sum);...//不停重复两行代码 如果要实现8组数的和,就需要16行代码,实现的越多,代码行也就越多.所以我们可以把完成特定功能的代码块放到一个函数里面去,直接调用这个函数,就省去重复输入大量代码的麻烦.使用函数完成:function add2(a,b){ sum=a+b; alert(sum);}//只需要调

javascript入门及数据类型

试了下,js脚本除了不能在当前页面的title标签中,当前页面哪都可以放.但是还是规矩的安置为好. a标签href属性放个脚本还是很不错的. 1 <a href="javascript:alert('还能这样用');">点我</a> 当使用如下方法来引入外部的js文件时,script标签就不能包含任何代码了 1 <script type="text/javascript" src="./bootstrap.min.js&quo

JavaScript 进阶篇的学习~

---恢复内容开始--- 让你认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面而已.我们还需使用JavaScript增加行为,为网页添加动态效果.准备好,让JavaScript带你进入新境界吧! JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等