JavaScript的two-sum问题解法
一个很常见的问题,找出一个数组中和为给定值的两个数的下标。为了简单一般会注明解只有一个之类的。
最容易想到的方法是循环遍历,这里就不说了。
在JS中比较优雅的方式是利用JS的对象作为hash的方式:
var twoSum = function(nums, target) {
var hash = {};
var i;
for (var i = 0; i < nums.length; i++ ) {
if (typeof hash[nums[i]] !== "undefined") {
return [i, hash[nums[i]]];
}
hash[target - nums[i]] = i;
}
};
这里面还可以做一些小的优化,比如把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循环里的执行代码比较简单。如果耗时主要在每个循环里的话,这招就不太管用了听说。
于是我照着介绍的例子,把上面的代码改写了一下:
var twoSum1 = function(nums, target) {
var hash = {};
var i = 0;
var startIndex = nums.length % 8;
var iterations = nums.length / 8;
do {
switch(startIndex) {
case 0: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 7: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 6: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 5: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 4: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 3: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 2: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
case 1: if(typeof hash[nums[i]] !== "undefined") {return [i, hash[nums[i]]]} hash[target - nums[i]] = i; i++;
}
} while (--iterations);
};
嗯,看上去很厉害的样子。接下来在浏览器里测试一下:
先构造一个长度为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%……
想到更快的方法再更………………
JavaScript的two-sum问题解法的更多相关文章
- JavaScript中大数相加的解法
一.两个大正整数字符串相加 在JavaScript中,数值类型满足不了大数据容量计算,可以用字符串进行操作 function add(strNum1, strNum2) { // 将传进来的数字/数字 ...
- Max double slice sum 的解法
1. 上题目: Task description A non-empty zero-indexed array A consisting of N integers is given. A tripl ...
- [LintCode] Continuous Subarray Sum II
Given an integer array, find a continuous rotate subarray where the sum of numbers is the biggest. Y ...
- 5、JavaScript进阶篇②——函数、事件、内置对象
一.函数 1. 什么是函数 函数的作用,可以写一次代码,然后反复地重用这个代码. 如:我们要完成多组数和的功能. var sum; sum = 3+2; alert(sum); sum=7+8 ; a ...
- 4、JavaScript进阶篇①——基础语法
一.认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面 ...
- JavaScript学习笔记 - 进阶篇(1)- JS基础语法
前言 JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等) JS进阶篇学习什么? 在JavaS ...
- Javascript进阶篇——(函数)笔记整理
这节是根据慕课网和JavaScript DOM编程艺术一书加起来做的笔记 什么是函数如果需要多次使用同一段代码,可以把它们封装成一个函数.函数(function)就是一组允许在你的代码里随时调用的语句 ...
- Javascript进阶篇——(流程控制语句)笔记整理
做判断(if语句)if语句是基于条件成立才执行相应代码时使用的语句.语法: if(条件){ 条件成立时执行代码 } 例子:假设你应聘web前端技术开发岗位,如果你会HTML技术,你面试成功,欢迎加入公 ...
- JavaScript进阶(四)
现在说说什么是函数.函数的作用可以写一次代码,然后反复的重用这个代码.如:我们要完成多组数和的功能.var sum;sum=3+2;alert(sum); sum=7+8;alert(sum);... ...
- JavaScript进阶--慕课网学习笔记
JAVASCRIPT—进阶篇 给变量取个名字(变量命名) 变量名字可以任意取,只不过取名字要遵循一些规则: 1.必须以字母.下划线或美元符号开头,后面可以跟字 ...
随机推荐
- 谈谈iOS Animation
零.前言 这里没有太多的代码细节,只是探索iOS动画的基本概念,以及其抽象模型,数学基础等.我们学习一个知识的时候一般有两个部分,抽象部分和形象部分,抽象好比语言的语法,是规则,形象好比具体的句子,可 ...
- 3.C#面向对象基础聊天机器人
基于控制台的简单版的聊天机器人,词库可以自己添加. 聊天机器人1.0版本 源码如下: using System; using System.Collections.Generic; using Sys ...
- es6学习笔记一数组(上)
最近公司没什么事情,我们老大让我看看es6,小颖就练习了下数组的各个方法,今天先给大家分享一部分.嘻嘻,希望对大家有所帮助. every方法: 概述: every() 方法测试数组的所有元素是否 ...
- 你究竟有多了解Spring?
曾经在一本书上看到这么一句话: 一个程序员的能力不在于增加代码的能力,而在于减少代码的能力. 基于以上我认之为真的命题,我经常问和我一起工作的程序员:你的程序还能不能精简一点?如果能,那能不能再精简一 ...
- webapi的学习资料
猿教程_-webapi教程-WebAPI教程 猿教程_-webapi教程-Web API概述 猿教程_-webapi教程-新建Web Api项目 猿教程_-webapi教程-测试Web API 猿教程 ...
- ToolsCodeTemplate使用
最近学习使用CodeSmith代码生成器 CodeSmith 是一种语法类似于asp.net的基于模板的代码生成器,程序可以自定义模板,从而减少重复编码的劳动量,提高效率. 作用:CodeSmith ...
- 黑马程序员——ARC机制总结和用ARC建立模型
ARC 全称:Automatic Reference Counting 使用ARC 只需要在建立一个新的项目的时候把 下面的√打上 Xcode5以后都会默认建议开发者使用ARC机制 新的项目中如果有部 ...
- HTTPS是数据交互细节
by http://www.zcfy.cc/article/how-does-https-work-1280.html 密码(Cipher) Java 1.2内置了一个叫做"JCE" ...
- Java - I/O
File类 java.io 操作文件和目录,与平台无关.具体的常用实例方法: File file = new File("."); // 以当前路径创建名为 ".&quo ...
- 在Wcf中应用ProtoBuf替代默认的序列化器
Google的ProtoBuf序列化器性能的牛逼已经有目共睹了,可以把它应用到Socket通讯,队列,Wcf中,身为dotnet程序员一边期待着不久后Grpc对dotnet core的支持更期待着Wc ...