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

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

在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问题解法的更多相关文章

  1. JavaScript中大数相加的解法

    一.两个大正整数字符串相加 在JavaScript中,数值类型满足不了大数据容量计算,可以用字符串进行操作 function add(strNum1, strNum2) { // 将传进来的数字/数字 ...

  2. Max double slice sum 的解法

    1. 上题目: Task description A non-empty zero-indexed array A consisting of N integers is given. A tripl ...

  3. [LintCode] Continuous Subarray Sum II

    Given an integer array, find a continuous rotate subarray where the sum of numbers is the biggest. Y ...

  4. 5、JavaScript进阶篇②——函数、事件、内置对象

    一.函数 1. 什么是函数 函数的作用,可以写一次代码,然后反复地重用这个代码. 如:我们要完成多组数和的功能. var sum; sum = 3+2; alert(sum); sum=7+8 ; a ...

  5. 4、JavaScript进阶篇①——基础语法

    一.认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面 ...

  6. JavaScript学习笔记 - 进阶篇(1)- JS基础语法

    前言 JavaScript能做什么? 1.增强页面动态效果(如:下拉菜单.图片轮播.信息滚动等) 2.实现页面与用户之间的实时.动态交互(如:用户注册.登陆验证等) JS进阶篇学习什么? 在JavaS ...

  7. Javascript进阶篇——(函数)笔记整理

    这节是根据慕课网和JavaScript DOM编程艺术一书加起来做的笔记 什么是函数如果需要多次使用同一段代码,可以把它们封装成一个函数.函数(function)就是一组允许在你的代码里随时调用的语句 ...

  8. Javascript进阶篇——(流程控制语句)笔记整理

    做判断(if语句)if语句是基于条件成立才执行相应代码时使用的语句.语法: if(条件){ 条件成立时执行代码 } 例子:假设你应聘web前端技术开发岗位,如果你会HTML技术,你面试成功,欢迎加入公 ...

  9. JavaScript进阶(四)

    现在说说什么是函数.函数的作用可以写一次代码,然后反复的重用这个代码.如:我们要完成多组数和的功能.var sum;sum=3+2;alert(sum); sum=7+8;alert(sum);... ...

  10. JavaScript进阶--慕课网学习笔记

                         JAVASCRIPT—进阶篇 给变量取个名字(变量命名) 变量名字可以任意取,只不过取名字要遵循一些规则: 1.必须以字母.下划线或美元符号开头,后面可以跟字 ...

随机推荐

  1. 原生JS封装Ajax插件(同域&&jsonp跨域)

    抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...

  2. 【Python五篇慢慢弹(3)】函数修行知python

    函数修行知python 作者:白宁超 2016年10月9日21:51:52 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondoc ...

  3. ASP.NET Core 中文文档 第二章 指南(4.1)ASP.NET Core MVC 与 Visual Studio 入门

    原文:Getting started with ASP.NET Core MVC and Visual Studio 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:刘怡(Alex ...

  4. Windows下Memcached安装与配置实例

    环境声明: 服务器: Windows Server 2008r2: Memcached: Memcached 64-bit for Windows(64位) From: http://www.urie ...

  5. Rafy 框架 - 使用 SqlTree 查询

    本文介绍如何使用 Rafy 框架中的 Sql Tree 查询: 除了开发者常用的 Linq 查询,Rafy 框架还提供了 Sql 语法树的方式来进行查询. 这种查询方式下,开发者不需要直接编写真正的 ...

  6. asp.net core 简单部署

    目的 练习asp.net core的技术使用.部署等.目前拥有一台阿里云服务器(超级低配版本),安装了centos系统,打算将练习项目发布到该环境中.可能需要做以下准备工作. 以前没接触过linux正 ...

  7. session的使用方法详解

    session的使用方法详解 Session是什么呢?简单来说就是服务器给客户端的一个编号.当一台WWW服务器运行时,可能有若干个用户浏览正在运正在这台服务器上的网站.当每个用户首次与这台WWW服务器 ...

  8. Json CPP 中文支持与入门示例

    在每一个Json Cpp自带*.cpp文件头加上: #include "stdafx.h" 将Json Cpp对自带的头文件的引用修改为单引号方式,例如json_reader.cp ...

  9. 做linux运维工程师,必须要掌握以下几个工具

    linux系统如果是学习可以选用redhat或centos,特别是centos在企业中用得最多,当然还会有其它版本的,但学习者还是以这2个版本学习就行,因为这两个版本都是兄弟,没区别的,有空可以再研究 ...

  10. jQuery fsBanner 手风琴

    fsbanner是一款自定义功能丰富的响应式网站Banner手风琴特效jQuery插件.该手风琴特效兼容性很好,支持点击和鼠标滑过等触发事件,并且可添加标题或描述. 在线实例 默认 带标题 鼠标滑过 ...