https://leetcode-cn.com/problemset/database/

---------------------------------------------------------------------------------

转载, 原文:https://www.cnblogs.com/By-ruoyu/p/11311830.html

最近开始重拾算法,在 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. 自己实现针对题目更高效的哈希算法。

【版权声明】  本博客版权归作者和博客园共有,作品来自于长沙.NET技术社区成员【吴俊毅】,有兴趣了解长沙.NET技术社区详情,请关注公众号【DotNET技术圈】

https://leetcode-cn.com/problemset/database/

leetcode-cn上面刷题的更多相关文章

  1. LeetCode面试常见100题( TOP 100 Liked Questions)

    LeetCode面试常见100题( TOP 100 Liked Questions) 置顶 2018年07月16日 11:25:22 lanyu_01 阅读数 9704更多 分类专栏: 面试编程题真题 ...

  2. onhashchange事件,只需要修改hash值即可响应onhashchange事件中的函数(适用于上一题下一题和跳转页面等功能)

    使用实例: 使用onhashchange事件做一个简单的上一页下一页功能,并且当刷新页面时停留在当前页 html: <!DOCTYPE html><html><body& ...

  3. LeetCode高频148错题记录

    3. Max Points on a Line 共线点个数3种解法 思路一:思考如何确定一条直线,两点法,确定斜率后带入一点.有三种情况,1. 两点重合,2. 斜率不存在,3. 正常算,依次以每个点为 ...

  4. CodeForces813E:Army Creation (主席树---上一题的加强版)

    As you might remember from our previous rounds, Vova really likes computer games. Now he is playing ...

  5. LeetCode上并发题目无Go版本:台湾同胞试水 — 交替打印FooBar

    https://mp.weixin.qq.com/s/I5va3PI1oGIj8R_n3Nw2yw

  6. [LeetCode] 接雨水,题 Trapping Rain Water

    这题放上来是因为自己第一回见到这种题,觉得它好玩儿 =) Trapping Rain Water Given n non-negative integers representing an eleva ...

  7. 每日温度(LeetCode Medium难度算法题)题解

    LeetCode 题号739中等难度 每日温度 题目描述: 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 ...

  8. 我在LeetCode的首次刷题

    到现在为止,我才发现我的博客一篇感受,心得,体会之言都没有. 今天就来随便扯扯. 刷题,是我最近一直在干的事情.也就每天写一两个.忘了就没写这种.也收藏了好几个刷题网站,当然第一次接触肯定是 WUST ...

  9. 2019招商银行M-Geeker线上比赛题解析

    目录 1. 最大子序和(变体) 2. 矩阵求乘积最大 3. 逐渐平均--值最大 目前已更新:第一题,第二题,第四题 1. 最大子序和(变体) 题目描述: 首先考虑常规的最大子序和的问题,即不能去掉中间 ...

随机推荐

  1. 高级UI-SVG

    栅格图可以实现图片的清晰显示,但这也意味着如果要在各种设备上使用栅格图,那么在使用的时候就会产生为了适配各种尺寸的设备而增加大量不同规格的栅格图,这也直接导致了资源文件体积的增大,矢量图就不存在这个问 ...

  2. ztree节点名称排序

    // result 为后台返回的集合,在渲染tree前的数据 result = result.sort(function (a, b) { // 判断前面一个是字母,后面一个不是字母,那么不换位置,返 ...

  3. code and dataset resources of computer vision

    From:http://rogerioferis.com/VisualRecognitionAndSearch2014/Resources.html Source Code Non-exhaustiv ...

  4. [转帖]MyCat教程【简单介绍】

    MyCat教程[简单介绍] 2019-10-15 10:27:23 波波烤鸭 阅读数 618 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. ...

  5. JqueryMobile与php跳转问题

    JqueryMobile提交表单到php时,会出现空白页面,需要手动刷新才会显示php页面. 修正方法:form元素中添加data-ajax=“false”. 具体原理:https://blog.cs ...

  6. 20191125:Python中的上下文管理机制with

    20191125:with上下文管理 with是一个上下文管理器,用于执行代码块所需要的运行的时候的上下文入口和出口.上下文管理器的典型用法包括保存和还原各种全局状态,锁定和解锁资源,关闭打开的文件等 ...

  7. python技巧 — Chrome浏览器中的 XPath Helper

    用于XPath 爬取网页结构的时候使用, 安装后 快捷键调用 左边 ctrl+ shift+x 启动 安装流程: 1. 打开chrome浏览器,扩展程序 .搜索 XPath Helper 下载安装(前 ...

  8. 根据IP获取国家,市区,经纬度等的免费库

    https://dev.maxmind.com/geoip/geoip2/geolite2/ 此网站上有提供SDK版,访问在线服务,也有离线版,下载库到本地,使用相应语言解析库

  9. Dockerfile编写,以及设置一个自启动脚本

    FROM:指定基础镜像,必须为第一个命令 MAINTAINER: 维护者信息 RUN:构建镜像时执行的命令 ADD:将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问 ...

  10. shell 学习笔记5-shell-if语句

    一.if条件语句 1.语法 1)单分支结构 第一种 if <条件表达式> then 指令 fi 第二种 if <条件表达式>:then 指令 fi 上文的"<条 ...