最近开始重拾算法,在 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%

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

写在最后

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

  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. CSS3 - vue中纯css实现柱状图表效果

    背景 以前我们制作柱状图都用echarts或者其他同类型的图表插件 这次是个移动端的需求,而且这个图表需要动画 使用echarts就会显得过重,而且动画达不到我想要的效果(主要是我自己愚蠢想不到好的动 ...

  2. POJ 3686:The Windy's(最小费用最大流)***

    http://poj.org/problem?id=3686 题意:给出n个玩具和m个工厂,每个工厂加工每个玩具有一个时间,问要加工完这n个玩具最少需要等待的平均时间.例如加工1号玩具时间为t1,加工 ...

  3. web前端css(二)

    一.  标准文档流 标准文档流中会有一些现象: 空白折叠 和 高低不齐边底对齐的现象 标准文档流等级森严, 标签分为两种等级: 行内元素 和 块级元素. 1. 行内元素 和 块级元素的区别: 行内元素 ...

  4. Oracle数据库---游标

    --查询所有员工的员工号.姓名和职位的信息.DECLARE --定义游标 CURSOR emp_cursor IS SELECT empno,ename,job FROM emp; v_empno e ...

  5. lleetcode 1 two sum c++

    Problem describe:https://leetcode.com/problems/two-sum/ Given an array of integers, return indices o ...

  6. 你不得不知的几个互联网ID生成器方案

    服务化.分布式已成为当下系统开发的首选,高并发操作在数据存储时,需要一套id生成器服务,来保证分布式情况下全局唯一性,以确保系统的订单创建.交易支付等场景下数据的唯一性,否则将造成不可估量的损失. 基 ...

  7. C#开发中常用的加密算法总结

    相信很多人在开发过程中经常会遇到需要对一些重要的信息进行加密处理,今天给大家分享我个人总结的一些加密算法: 常见的加密方式分为可逆和不可逆两种方式 可逆:RSA,AES,DES等 不可逆:常见的MD5 ...

  8. Java编程思想:内部类其他知识点

    public class Test { public static void main(String[] args) { // InheritInner.test(); // EggTest.test ...

  9. textarea 绕过jq验证的方法,提交空值

    <textarea placeholder=" aria-required="true" aria-describedby="OtherNotes-err ...

  10. MD5的简单用法

    非常简单的MD5加密和解密(即用即copy) 点击帮助灯泡引用就可使用 //生成MD5帮助文件文件 public class MD5Help{ ///MD5加密 方法类 public static s ...