最近开始重拾算法,在 LeetCode上刷题。顺便也记录下解题报告以及优化思路。

题目链接:1.两数之和

题意

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

  1. nums = [2, 7, 11, 15], target = 9
  2. 返回 [0, 1]

题意很简单,就是寻找两个数,这两个数相加的值等于 target。且保证每组输入一定会有答案。

解题思路

从题意上看, 只需要找到那两个数即可。那么首先可以想到的就是枚举组合两个数的和,但是 组合数 的数量是非常大的,这个思路就可以作罢。

两个数相加的和等于 target, 反过来,对于一个数 nums[i],能否在数组里找到另外一个数 nums[j] 使得 nums[j] = target - nums[i]。这样我们只需要关心一个数即可。

暴力枚举

简单粗暴,一重循环用来枚举 nums[i], 另一重用来寻找 nums[j]

代码:

  1. public class Solution {
  2. public int[] TwoSum(int[] nums, int target) {
  3. for(int i = 0; i < nums.Length; i ++) {
  4. int res = target - nums[i];
  5. for(int j = 0; j < nums.Length; j ++) {
  6. if(i == j) continue;
  7. if(res == nums[j]) return new int[] {i, j};
  8. }
  9. }
  10. return new int[] {};
  11. }
  12. }

执行用时: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>

代码:

  1. public class Solution
  2. {
  3. public int[] TwoSum(int[] nums, int target)
  4. {
  5. var dic = new Dictionary<int, List<int>>();
  6. for(int i = 0; i < nums.Length; i ++)
  7. {
  8. int num = nums[i];
  9. int res = target - num;
  10. if(dic.ContainsKey(res))
  11. {
  12. return new int[] {i, dic[res][0]};
  13. }
  14. if(!dic.ContainsKey(num))
  15. {
  16. dic.Add(num, new List<int>(){});
  17. }
  18. dic[num].Add(i);
  19. }
  20. return new int[] {};
  21. }
  22. }

执行用时:468 ms

内存消耗:30.5MB

用时排名:超过78.61%

改进后的算法排名与之前可谓是天差地别,已经到了前 30%

仅仅是达到了前三分之一,说明这个算法还有可以更进一步的优化。

进一步优化查询

这里用了 Dictionary, 但这里的 TValue 是一个列表。仔细想想,这里我们是不需要保存列表的,只需要保存一个值即可,因为只需要找到一组答案即可!

其次可以减去第二个判断,并不需要判断是否存在,直接覆盖/新建即可。

最后可以反向查询,查之前的数值中是否缺一个 nums[i],对应存进去的就是差值,这样可以减去两个临时变量,顺带优化一点点的空间。

代码:

  1. public class Solution
  2. {
  3. Dictionary<int, int> dic = new Dictionary<int, int>();
  4. public int[] TwoSum(int[] nums, int target)
  5. {
  6. if(nums.Length == 2) return new int[] {0, 1};
  7. dic.Clear();
  8. for (int i = 0; i < nums.Length; i++)
  9. {
  10. if(dic.ContainsKey(nums[i])) return new int[] {dic[nums[i]], i};
  11. dic[target - nums[i]] = i;
  12. }
  13. return new int[] { };
  14. }
  15. }

执行用时:360 ms

内存消耗:30MB

用时排名:超过98.83%

改进后的算法相比之前的差距并不是非常的大,但就是这百来毫秒的差距,排名上升到了前 3%

这个算法还是有可以改进的地方,但是若羽现在暂时还没有思路如何再进一步将查询复杂度降下去,这里可能需要自己实现一个更高效的哈希算法。

写在最后

许久没有接触算法了,有些生疏,思路上也有些堵塞。这里若羽对于接下来进一步优化有一些初步的想法,待有空实验后再加一篇解题报告。

  1. 分段策略,当数据量达到一定程度时使用更高效的算法,当数据量较小时,可能哈希耗时会更长一些,这个需要实验。大意便是寻找多个算法的耗时阈值,利用阈值进行策略选择。

  2. 自己实现针对题目更高效的哈希算法。

LeetCode :1.两数之和 解题报告及算法优化思路的更多相关文章

  1. LeetCode :2.两数相加 解题报告及算法优化思路

    题目连接:2.两数相加 题意 题目难度标为 中等, 因为题意上有一部分理解难度,以及需要数据结构的链表基础. 还不知道到链表的童鞋可以粗略的看下百度百科或者是翻出数据结构的书看一看,通俗一点的语言来解 ...

  2. 前端与算法 leetcode 1. 两数之和

    目录 # 前端与算法 leetcode 1. 两数之和 题目描述 概要 提示 解析 解法一:暴力法 解法二:HashMap法 算法 传入[1, 2], [11, 1, 2, 3, 2]的运行结果 执行 ...

  3. LeetCode:两数之和、三数之和、四数之和

    LeetCode:两数之和.三数之和.四数之和 多数之和问题,利用哈希集合减少时间复杂度以及多指针收缩窗口的巧妙解法 No.1 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在 ...

  4. Leetcode 001. 两数之和(扩展)

    1.题目要求 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 2.解法一:暴力法(for*for,O(n*n)) ...

  5. LeetCode 653. 两数之和 IV - 输入 BST(Two Sum IV - Input is a BST)

    653. 两数之和 IV - 输入 BST 653. Two Sum IV - Input is a BST 题目描述 给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定 ...

  6. leetCode:twoSum 两数之和 【JAVA实现】

    LeetCode 两数之和 给定一个整数数组,返回两个数字的索引,使它们相加到特定目标. 您可以假设每个输入只有一个解决方案,并且您可能不会两次使用相同的元素. 更多文章查看个人博客 个人博客地址:t ...

  7. Leetcode 1. 两数之和 (Python版)

    有粉丝说我一个学算法的不去做Leetcode是不是浪费,于是今天闲来没事想尝试一下Leetcode,结果果断翻车,第一题没看懂,一直当我看到所有答案的开头都一样的时候,我意识到了我是个铁憨憨,人家是让 ...

  8. 每天一道面试题LeetCode 01 -- 两数之和

    Two Sum 两数之和 Given an array of integers, find two numbers such that they add up to a specific target ...

  9. Leetcode 167. 两数之和 II - 输入有序数组 By Python

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值 ...

随机推荐

  1. CentOS下安装配置MySQL8.0的步骤详解

    下载yum源的安装包 yum localinstall https://repo.mysql.com//mysql80-community-release-el7-1.noarch.rpm 安装 yu ...

  2. Python开发【第七篇】: 面向对象和模块补充

    内容概要 特殊成员 反射 configparser模块 hashlib模块 logging模块 异常处理 模块 包 1. 特殊成员 什么是特殊成员呢? __init_()就是个特殊的成员. 带双下划线 ...

  3. 大数据虚拟混算平台Moonbox配置指南

    一.环境准备 已安装Apache Spark 2.2.0(此版本仅支持Apache Spark 2.2.0, 其他Spark 版本后续会兼容) 已安装MySQL并启动,且开启远程访问 各安装节点已经配 ...

  4. Shiro中@RequiresAuthentication等等注解介绍

    使用前请先开启Shiro的controller层注解,如果已经设置请下滑绕过 要在spring-mvc.xml中写. <!--下面的用于开启shiro的权限注解--> <bean c ...

  5. 【tf.keras】在 cifar 上训练 AlexNet,数据集过大导致 OOM

    cifar-10 每张图片的大小为 32×32,而 AlexNet 要求图片的输入是 224×224(也有说 227×227 的,这是 224×224 的图片进行大小为 2 的 zero paddin ...

  6. Windows Presentation Foundation (WPF) 项目中不支持xxx的解决

    一般Windows Presentation Foundation (WPF) 项目中不支持xxx都是由于没引用相应的程序集导致,比如Windows Presentation Foundation ( ...

  7. 个人永久性免费-Excel催化剂功能第90波-xml与json数据结构转换表格结构

    在网络时代,大量的数据交互以xml和json格式提供,特别是系统间的数据交互和网络WebAPI.WebService接口的数据提供,都是通过结构化的xml或json提供给其他应用调用返回数据.若能提供 ...

  8. 个人永久性免费-Excel催化剂功能第88波-批量提取pdf文件信息(图片、表格、文本等)

    日常办公场合中,除了常规的Excel.Word.PPT等文档外,还有一个不可忽略的文件格式是pdf格式,而对于想从pdf文件中获取信息时,常规方法将变得非常痛苦和麻烦.此篇给大家送一pdf文件提取信息 ...

  9. Excel催化剂开源第31波-pdf相关功能实现及类库介绍

    在Excel催化剂刚推出的pdf相关功能中,反馈很热烈,不止是用户层面好多人喜欢,也听到在.NET开发群里有询问pdf在winform上展现的功能诉求,一段时间没写开源篇,生怕大家以为Excel催化剂 ...

  10. SpringBoot2.0集成WebSocket,实现后台向前端推送信息

    感谢作者,支持原创: https://blog.csdn.net/moshowgame/article/details/80275084 什么是WebSocket? WebSocket协议是基于TCP ...