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.必须以字母.下划线或美元符号开头,后面可以跟字 ...
随机推荐
- 1.JAVA之GUI编程概述
下列内容为本人看毕向东老师java视频教程学习笔记! JAVA GUI图形用户界面编程: Windows 操作系统提供两种操作方式: ...
- spring整合mybatis使用<context:property-placeholder>时的坑
背景 最近项目要上线,需要开发一个数据迁移程序.程序的主要功能就是将一个数据库里的数据,查询出来经过一系列处理后导入另一个数据库.考虑到开发的方便快捷.自然想到用spring和mybatis整合一下. ...
- 使用VS Code从零开始开发调试.NET Core 1.0
使用VS Code 从零开始开发调试.NET Core 1.0. .NET Core 是一个开源的.跨平台的 .NET 实现. VS Code 全称是 Visual Studio Code,Visua ...
- MVC5+EF6+AutoMapper+Bootstrap打造在线博客(1.1)
DAL层的三个Model类: 字典表:CFDict 用户表:CFUser 用户爱好表:CFUserHobby(关联cfuser表和cfdict表) CFUser表和CFUserHobby表是一对多关系 ...
- .net 预防用户复制页面地址直接进入
用户将某一页面的地址直接复制到另一个浏览器窗口(或者将链接地址分享给其他人),假如页面需要参数的时候因为直接进入没有从其他页面跳转,参数不存在,可能得不到想要的结果 处理方法:让页面跳到首页重新进入: ...
- jQuery+CSS3文字跑马灯特效
jQuery+CSS3文字跑马灯特效是一款将跑马灯背景制作为3D立方体效果,文字在上面移动时,就像是文字投影到墙壁上,在转角出会改变运动方向. 效果展示 http://hovertree.com/te ...
- C#开发微信门户及应用(32)--微信支付接入和API封装使用
在微信的应用上,微信支付是一个比较有用的部分,但也是比较复杂的技术要点,在微商大行其道的年代,自己的商店没有增加微信支付好像也说不过去,微信支付旨在为广大微信用户及商户提供更优质的支付服务,微信的支付 ...
- Servlet3.0的异步
servlet之前的操作同时同步的,就是按照这样的一个流程来走的: 1.请求根据一个路径路由到一个servlet中, 2.servlet获取一系列的参数 3.执行一系列的逻辑(花费时间所占的比重也更大 ...
- SharePoint Server2016的User Profile Services服务
前言SharePoint Server 的早期版本具有内置的 ForeFront Identity Manager (FIM) 副本,可在 SharePoint Server 服务器产品内运行.具 ...
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...