LeetCode :1.两数之和 解题报告及算法优化思路
最近开始重拾算法,在 LeetCode
上刷题。顺便也记录下解题报告以及优化思路。
题目链接:1.两数之和
题意
给定一个整数数组 nums
和一个目标值 target
,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
nums = [2, 7, 11, 15], target = 9
返回 [0, 1]
题意很简单,就是寻找两个数,这两个数相加的值等于 target
。且保证每组输入一定会有答案。
解题思路
从题意上看, 只需要找到那两个数即可。那么首先可以想到的就是枚举组合两个数的和,但是 组合数 的数量是非常大的,这个思路就可以作罢。
两个数相加的和等于 target
, 反过来,对于一个数 nums[i]
,能否在数组里找到另外一个数 nums[j]
使得 nums[j] = target - nums[i]
。这样我们只需要关心一个数即可。
暴力枚举
简单粗暴,一重循环用来枚举 nums[i]
, 另一重用来寻找 nums[j]
。
代码:
public class Solution {
public int[] TwoSum(int[] nums, int target) {
for(int i = 0; i < nums.Length; i ++) {
int res = target - nums[i];
for(int j = 0; j < nums.Length; j ++) {
if(i == j) continue;
if(res == nums[j]) return new int[] {i, j};
}
}
return new int[] {};
}
}
执行用时:904ms
内存消耗:29.6MB
用时排名:超过21.29%
29个案例,耗时近 1 秒。 由于这里仅有循环辅助变量,内存消耗其实不大。
耗时排名是排在比较后面的,这也说明了还有更优的解法。
空间换时间
此题关键的地方在于:如何快速的找到 j
,暴力枚举在最坏的情况下会找遍整个数组,直到最后一个才找到,时间复杂度也就是 O(n)
。
那么,在这里我们可以利用 哈希算法
进行映射,从而达到更快查找效率。理论上 哈希算法
设计良好的情况下可以达到 常数级 O(1)
的复杂度。
一个例子:在值不大的情况下, 可以用值当做数组下标,而数组的值作为原来数组的下标。即:
对于 x = nums[i]
,存在 hash[x] = i
。这样在牺牲大量空间的情况下可以使得查询效率达到极致的常数级 O(1)
。
但是很遗憾, 这道题并没有办法直接使用这个方法,因为 int.MaxValue
是远超过了数组可以定义的范围。编译时会报错,内存溢出。
既然暂时没有办法达到 O(1)
的地步, 那么可以考虑使用实现了 哈希算法
(这里保留说法,若羽源码没有阅读完,在看到index的取法有着很明显的哈希痕迹进行猜测的)的 Dictionary<TKey, TValue>
。
代码:
public class Solution
{
public int[] TwoSum(int[] nums, int target)
{
var dic = new Dictionary<int, List<int>>();
for(int i = 0; i < nums.Length; i ++)
{
int num = nums[i];
int res = target - num;
if(dic.ContainsKey(res))
{
return new int[] {i, dic[res][0]};
}
if(!dic.ContainsKey(num))
{
dic.Add(num, new List<int>(){});
}
dic[num].Add(i);
}
return new int[] {};
}
}
执行用时:468 ms
内存消耗:30.5MB
用时排名:超过78.61%
改进后的算法排名与之前可谓是天差地别,已经到了前 30%
。
仅仅是达到了前三分之一,说明这个算法还有可以更进一步的优化。
进一步优化查询
这里用了 Dictionary
, 但这里的 TValue
是一个列表。仔细想想,这里我们是不需要保存列表的,只需要保存一个值即可,因为只需要找到一组答案即可!
其次可以减去第二个判断,并不需要判断是否存在,直接覆盖/新建即可。
最后可以反向查询,查之前的数值中是否缺一个 nums[i]
,对应存进去的就是差值,这样可以减去两个临时变量,顺带优化一点点的空间。
代码:
public class Solution
{
Dictionary<int, int> dic = new Dictionary<int, int>();
public int[] TwoSum(int[] nums, int target)
{
if(nums.Length == 2) return new int[] {0, 1};
dic.Clear();
for (int i = 0; i < nums.Length; i++)
{
if(dic.ContainsKey(nums[i])) return new int[] {dic[nums[i]], i};
dic[target - nums[i]] = i;
}
return new int[] { };
}
}
执行用时:360 ms
内存消耗:30MB
用时排名:超过98.83%
改进后的算法相比之前的差距并不是非常的大,但就是这百来毫秒的差距,排名上升到了前 3%
。
这个算法还是有可以改进的地方,但是若羽现在暂时还没有思路如何再进一步将查询复杂度降下去,这里可能需要自己实现一个更高效的哈希算法。
写在最后
许久没有接触算法了,有些生疏,思路上也有些堵塞。这里若羽对于接下来进一步优化有一些初步的想法,待有空实验后再加一篇解题报告。
分段策略,当数据量达到一定程度时使用更高效的算法,当数据量较小时,可能哈希耗时会更长一些,这个需要实验。大意便是寻找多个算法的耗时阈值,利用阈值进行策略选择。
自己实现针对题目更高效的哈希算法。
LeetCode :1.两数之和 解题报告及算法优化思路的更多相关文章
- LeetCode :2.两数相加 解题报告及算法优化思路
题目连接:2.两数相加 题意 题目难度标为 中等, 因为题意上有一部分理解难度,以及需要数据结构的链表基础. 还不知道到链表的童鞋可以粗略的看下百度百科或者是翻出数据结构的书看一看,通俗一点的语言来解 ...
- 前端与算法 leetcode 1. 两数之和
目录 # 前端与算法 leetcode 1. 两数之和 题目描述 概要 提示 解析 解法一:暴力法 解法二:HashMap法 算法 传入[1, 2], [11, 1, 2, 3, 2]的运行结果 执行 ...
- LeetCode:两数之和、三数之和、四数之和
LeetCode:两数之和.三数之和.四数之和 多数之和问题,利用哈希集合减少时间复杂度以及多指针收缩窗口的巧妙解法 No.1 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在 ...
- Leetcode 001. 两数之和(扩展)
1.题目要求 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 2.解法一:暴力法(for*for,O(n*n)) ...
- LeetCode 653. 两数之和 IV - 输入 BST(Two Sum IV - Input is a BST)
653. 两数之和 IV - 输入 BST 653. Two Sum IV - Input is a BST 题目描述 给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定 ...
- leetCode:twoSum 两数之和 【JAVA实现】
LeetCode 两数之和 给定一个整数数组,返回两个数字的索引,使它们相加到特定目标. 您可以假设每个输入只有一个解决方案,并且您可能不会两次使用相同的元素. 更多文章查看个人博客 个人博客地址:t ...
- Leetcode 1. 两数之和 (Python版)
有粉丝说我一个学算法的不去做Leetcode是不是浪费,于是今天闲来没事想尝试一下Leetcode,结果果断翻车,第一题没看懂,一直当我看到所有答案的开头都一样的时候,我意识到了我是个铁憨憨,人家是让 ...
- 每天一道面试题LeetCode 01 -- 两数之和
Two Sum 两数之和 Given an array of integers, find two numbers such that they add up to a specific target ...
- Leetcode 167. 两数之和 II - 输入有序数组 By Python
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值 ...
随机推荐
- HTML5新增的表单验证功能
一.HTML5表单的特点: HTML5 表单增加了许多内置的控件和控件属性 XHTML 中需要放在 form 之中的诸如 input/button/select/textarea 等标签元素,在 HT ...
- 02-三种Bean装配机制(二)
上一篇已经介绍了自动化装配https://www.cnblogs.com/fionyang/p/11123900.html 接下来就要介绍两种显示装配的方式了,分别是java代码装配和XML文件装配. ...
- HDU 6060:RXD and dividing(DFS)
题目链接 题意 给出n个点,要把除1以外的点分成k个集合,然后对于每个集合要和1这个点一起求一个最小生成树,然后问这k个最小生成树的最大总和是多少. 思路 因为每个集合都包含1这个点,因此对于每个点都 ...
- c++学习书籍推荐《C++设计新思维》下载
百度云及其他网盘下载地址:点我 译序by 侯捷 i 译序by 於春景 iii 目录 v 序言by scott meyers xi 序言by john vlissides xv 前言 xvii 致谢 x ...
- Spring源码阅读-ApplicationContext体系结构分析
目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...
- PYTHONIOENCODING = UTF-8 引发的血案
血案: 我就是想在Jenkins上运行一段自动化python代码,就是最简单的本地控制台输出, 我就不懂了它为什么一直是去找 cp1252.py 编码???目前, 确定 pycharm 运行脚本很OK ...
- 一台服务器通过nginx配置多个域名(80端口)
1. 问题描述 多个域名对应一个服务器,为了避免域名后增加端口号,两个域名都需要占用80端口号,使用nginx来进行配置. 2. 解决方案 目前项目中,线上正在使用(100%可用)多域名对应一个服务器 ...
- NOIP 2004 虫食算题解
问题 E: [Noip2004]虫食算 时间限制: 1 Sec 内存限制: 128 MB 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一 ...
- Specifying the Code to Run on a Thread
This lesson shows you how to implement a Runnable class, which runs the code in its Runnable.run() m ...
- 学习4:总结# 1.列表 # 2.元祖 # 3.range
列表 -- list 有序,可变的,索引, 作用:存储数据的,支持很多种数据类型 定义方式: lst = [1,"alex","黑哥"] 增: append 追 ...