LeetCode #001# Two Sum(js描述)
问题描述:https://leetcode.com/problems/two-sum/
思路1:暴力搜索
根据排列组合原理,列举Cn取2对数字,逐对进行判断,效率是O(n^2-1/2n),代码如下:
var twoSum = function(nums, target) {
for (let i = 0; i != nums.length; ++i) {
for (let j = i + 1; j != nums.length; ++j) {
if (nums[i] + nums[j] == target) {
return [i, j];
}
}
}
};
思路2:聪明一点的搜索
先将数组排序,这个nlgn内可以完成,然后弄两个下标分别指向头和尾,边做判断边根据判断结果缩小搜索范围,这样一般在扫描完整个数组之前(n以内)就可以找到相应元素了,不过需要额外的空间来保存元素和原下标间的映射关系。最终效率是O(nlgn):
// O(nlgn)
var twoSum2 = function(nums, target) {
let copy = nums.map((x, i) => {
return {
val: x,
index: i,
};
}); // 保存元素的下标值
copy.sort((a, b) => a.val - b.val); // 按照元素值从小到大排序 let i = 0, j = copy.length - 1;
let sum;
while ((sum = copy[i].val + copy[j].val) != target) {
sum > target ? j-- : i++;
} i = copy[i].index;
j = copy[j].index;
return i < j ? [i, j] : [j, i];
};
正确性我也是纠结了一会儿,毕竟数学很菜。。。所以给出一个乱七八糟。。又不严谨的。。。“证明”↓ 我们证明这个循环不变式:按照从有序数组的外围朝向内侧的搜索顺序,如果(sum = copy[i].val + copy[j].val) != target那么要找的元素一定在i+1..j或者i..j-1范围中,至于变化i还是j取决于copy[i].val + copy[j].val相对target是大了还是小了:大了一定减j,小了一定加i。 初始化:单看i=0以及j=copy.length - 1;的话是显然成立的,不过这属于特殊情况,属于没路走了,只能i+1或者j-1。选取一个稍普通些的情形i+1..j-1(i=0且j=copy.length - 1),这个时候i和j都是可进可退的,那么当sum > target的时候为什么一定是j-1-1而不是i+1-1呢(这两种操作都会让sum更接近target)?一个直觉且没毛病的理由是i..j-1在上个(或者上上个)迭代已经判断过了,所以此路明显不通,所以就只能是j-1-1了。然而我们需要考察更普通的情形,连续n次迭代sum都小于target,于是i先加了n,之后m次迭代sum都大于target,j才随后减去m,那么在j逐步-1的过程中i可不可以尝试回退一步(-1,回退n步和1步情形都是一样的,假设回退一步方便讨论)呢?因为这么做确实也让sum变小了,并且容易知道i+n-1..j-m这对数并没有判断过(i累计加了n的时候j仍可能还在原地踏步)。不妨假设[i+n-1, j-m]就是原问题的解,即i前进到i+n又回退到i+n-1并且copy[i+n-1].val + copy[j-m].val == target成立。仔细考察“有序数组”这一前置条件,会发现倘若i和j是原问题的解,也就是copy[i].val + copy[j].val == target成立,那么copy[i].val + copy[任何大于j的下标值].val总是大于target,这是因为copy[任何大于j的下标值].val > copy[j].val,言下之意,考虑最终的情形,必定i和j是有一方会先到达要找的元素之一且在原地等待,不存在什么走过头再回头的情形,于是就推翻假设了。。。此时已经考虑了所有情况,因此循环不变式成立。当sum < target时类似。 保持:假设对于某个i..j(i>0且j<copy.length - 1)循环不变式成立,也就是要找的元素一定在i+1..j或者i..j-1中。那么再进行一次迭代,也就是在i+1..j或者i..j-1中搜索,这又回到了初始化的情形,所以循环不变式仍然成立。 终止:因为题目确保了一定有那么一对元素存在,迭代终止的时候就是sun == target找到答案的时候。
思路3:利用HashMap巧解
事实上在给出target和一个元素后,另外一个元素就已经随之确定了。因此可以构建一个map,用另外一个元素的值作为key(或者自己本身的值),而value部分可以用来存当前元素的下标,这样一来,只需要至多扫描一遍数组(或者一遍以内),就可以得到答案了。效率是O(n)。js代码如下:
// O(n)
var twoSum3 = function(nums, target) {
let obj = {};
nums.forEach((x, i) => obj[target - x] = i);
for (let i = 0; i != nums.length; ++i) {
let j = obj[nums[i]];
if (j != undefined && j != i) {
return i < j ? [i, j] : [j, i];
}
}
}; // O(n),渐进性没有改善,不过去掉了一些尾巴
// Runtime: 52 ms, faster than 100.00% of JavaScript online submissions for Two Sum.
var twoSum4 = function(nums, target) {
let obj = {}, j; // 用obj作为map
for (let i = 0; i != nums.length; ++i) {
if ((j = obj[nums[i]]) != undefined) {
return [j, i];
}
obj[target - nums[i]] = i;
}
}; // 这个和上一个是一样的,纯粹为了测试一下用obj作map快还是new Map()快。结果是慢了一点。
var twoSum5 = function(nums, target) {
let map = new Map();
let obj = {}, j;
for (let i = 0; i != nums.length; ++i) {
if ((j = map.get(nums[i])) != undefined) {
return [j, i];
}
map.set(target - nums[i], i);
}
};
LeetCode #001# Two Sum(js描述)的更多相关文章
- 【JAVA、C++】LeetCode 001 Two Sum
Given an array of integers, find two numbers such that they add up to a specific target number. The ...
- [Leetcode][001] Two Sum (Java)
题目在这里: https://leetcode.com/problems/two-sum/ [标签]Array; Hash Table [个人分析] 这个题目,我感觉也可以算是空间换时间的例子.如果是 ...
- LeetCode 算法题解 js 版 (001 Two Sum)
LeetCode 算法题解 js 版 (001 Two Sum) 两数之和 https://leetcode.com/problems/two-sum/submissions/ https://lee ...
- 【LeetCode】1022. Sum of Root To Leaf Binary Numbers 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS 日期 题目地址:https://leetco ...
- 【LeetCode】985. Sum of Even Numbers After Queries 解题报告(C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 暴力 找规律 日期 题目地址:https://lee ...
- 【LeetCode】129. Sum Root to Leaf Numbers 解题报告(Python)
[LeetCode]129. Sum Root to Leaf Numbers 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.com/pr ...
- Java for LeetCode 216 Combination Sum III
Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...
- LeetCode 1 Two Sum 解题报告
LeetCode 1 Two Sum 解题报告 偶然间听见leetcode这个平台,这里面题量也不是很多200多题,打算平时有空在研究生期间就刷完,跟跟多的练习算法的人进行交流思想,一定的ACM算法积 ...
- [leetCode][013] Two Sum 2
题目: Given an array of integers that is already sorted in ascending order, find two numbers such that ...
随机推荐
- linux系统关闭指定服务的方式
1.根据名称称查找并关闭:pgrep -f 名称 | xargs kill -9 2.根据端口称查找并关闭:lsof -i:端口 | grep LISTEN|awk '{print $2}'|xarg ...
- Sping boot和mybatis整合
在没有配置数据库时,注释这样@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 接下来我们DataSourceA ...
- antd-mobile Picker组件默认值
import { createForm } from "rc-form"; @createForm() class TopAdSlots extends Component { @ ...
- 巧用border效果
目的: 我们在做css的时候为了提高网站的效率减少服务器请求,我们可以通过css来实现一些简单的图片特效,比如说三角形,这篇文章讲解的是通过边框实现不同的效果. 上面样式部分代码: <style ...
- python全栈开发 * 12 知识点汇总 * 180530
12 知识点总结 装饰器进阶 ⼀. 通⽤装饰器的回顾1.开闭原则: 对增加功能开放. 对修改代码封闭2.装饰器的作⽤: 在不改变原有代码的基础上给⼀个函数增加功能3.通⽤装饰器的写法:def wrap ...
- div加链接 html给div加超链接实现点击div跳转的方法[申明:来源于网络]
div加链接 html给div加超链接实现点击div跳转的方法[申明:来源于网络] 地址:http://www.cdxwcx.com/faq/htmldivLink.html
- C语言编程(多线程)
C语言中多线程编程包括的文件:#include<pthread.h>(linux环境下) pthread_t //线程函数返回类型 pthread_mutrex_t //互斥锁类型 int ...
- 我了解到的新知识之--GDPR
2018年5月25日GDPR正式实施,但是一直也是一知半解,今天偶然翻看到一篇企业撰写的关于GDPR的公众号文章,随即去网络上搜索了以下. 大家可以参考如下链接连接过于GDPR的细节,GDPR包括序言 ...
- 转 Kafka、RabbitMQ、RocketMQ等消息中间件的对比 —— 消息发送性能和优势
Kafka.RabbitMQ.RocketMQ等消息中间件的对比 —— 消息发送性能和优势 引言 分布式系统中,我们广泛运用消息中间件进行系统间的数据交换,便于异步解耦.现在开源的消息中间件有很多,前 ...
- 设计模式之——bridge模式
Bridge模式,又叫桥接模式,是针对同一接口进行扩展与实现操作的一种设计模式. 这种模式,与之前学过的适配器模式具有相似的地方,也有不同的地方,下面就让我们一一解析吧. 首先,我们要了解到,为什么需 ...