leetcode-cn上面刷题
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%
。
这个算法还是有可以改进的地方,但是若羽现在暂时还没有思路如何再进一步将查询复杂度降下去,这里可能需要自己实现一个更高效的哈希算法。
写在最后
许久没有接触算法了,有些生疏,思路上也有些堵塞。这里若羽对于接下来进一步优化有一些初步的想法,待有空实验后再加一篇解题报告。
分段策略,当数据量达到一定程度时使用更高效的算法,当数据量较小时,可能哈希耗时会更长一些,这个需要实验。大意便是寻找多个算法的耗时阈值,利用阈值进行策略选择。
自己实现针对题目更高效的哈希算法。
https://leetcode-cn.com/problemset/database/
leetcode-cn上面刷题的更多相关文章
- LeetCode面试常见100题( TOP 100 Liked Questions)
LeetCode面试常见100题( TOP 100 Liked Questions) 置顶 2018年07月16日 11:25:22 lanyu_01 阅读数 9704更多 分类专栏: 面试编程题真题 ...
- onhashchange事件,只需要修改hash值即可响应onhashchange事件中的函数(适用于上一题下一题和跳转页面等功能)
使用实例: 使用onhashchange事件做一个简单的上一页下一页功能,并且当刷新页面时停留在当前页 html: <!DOCTYPE html><html><body& ...
- LeetCode高频148错题记录
3. Max Points on a Line 共线点个数3种解法 思路一:思考如何确定一条直线,两点法,确定斜率后带入一点.有三种情况,1. 两点重合,2. 斜率不存在,3. 正常算,依次以每个点为 ...
- CodeForces813E:Army Creation (主席树---上一题的加强版)
As you might remember from our previous rounds, Vova really likes computer games. Now he is playing ...
- LeetCode上并发题目无Go版本:台湾同胞试水 — 交替打印FooBar
https://mp.weixin.qq.com/s/I5va3PI1oGIj8R_n3Nw2yw
- [LeetCode] 接雨水,题 Trapping Rain Water
这题放上来是因为自己第一回见到这种题,觉得它好玩儿 =) Trapping Rain Water Given n non-negative integers representing an eleva ...
- 每日温度(LeetCode Medium难度算法题)题解
LeetCode 题号739中等难度 每日温度 题目描述: 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数.如果之后都不会升高,请在该位置用 0 ...
- 我在LeetCode的首次刷题
到现在为止,我才发现我的博客一篇感受,心得,体会之言都没有. 今天就来随便扯扯. 刷题,是我最近一直在干的事情.也就每天写一两个.忘了就没写这种.也收藏了好几个刷题网站,当然第一次接触肯定是 WUST ...
- 2019招商银行M-Geeker线上比赛题解析
目录 1. 最大子序和(变体) 2. 矩阵求乘积最大 3. 逐渐平均--值最大 目前已更新:第一题,第二题,第四题 1. 最大子序和(变体) 题目描述: 首先考虑常规的最大子序和的问题,即不能去掉中间 ...
随机推荐
- Django:序列化的几种方法
前言 关于序列化操作,就是将一个可迭代的数据结构,通过便利的方式进行我们所需要的操作. 今天历来归纳一下,Django中的几种不同得分方法,已经Django-restframework提供的方法 创建 ...
- jvm(5)---垃圾回收(回收算法和垃圾收集器)
1.垃圾回收算法 1.1 标记-清除算法 算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象.它是最基础的收集算法,效率也很高,但是会带来两个明显的问题 ...
- 以Redis为例介绍YCSB的使用
环境 首先确保安装了jdk和maven,我个人使用的是openjdk11和maven3,由于本人非常建议使用python版本的ycsb,建议安装python.ubuntu 18.04下可以使用apt安 ...
- 关于TV工厂菜单参数的具体说明
1.ADC Adjust 此项是针对YPbPr.VGA端口进行处理的,在三路R/G/B或者YPb/Pr信号输入到芯片时候,由于存在硬件上的偏差,导致信号和标准信号存在偏差,需要对信号进行ADC校正.光 ...
- c++ 在Ubuntu系统中使用access函数
include<iostream> #include<stdlib.h> #include<stdio.h> #include<unistd.h> us ...
- 在 FR 网络配置 OSPF
一.环境准备 1. 软件:GNS3 2. 路由:c7200 二.实验操作 实验要求: 1.掌握配置帧中继的基本方法. 2.掌握在路由器中模拟帧中继交换机的方法. 3.掌握 NBMA 网络中 OSPF ...
- [转]PHP程序员的技术成长规划
转自:http://blog.leanote.com/post/darker/PHP%E7%A8%8B%E5%BA%8F%E5%91%98%E7%9A%84%E6%8A%80%E6%9C%AF%E6% ...
- myeclipse 相关问题
[如何设置 Tab 键为四个空格] https://blog.csdn.net/QQ826688096/article/details/90543252
- 关于wireshark的过滤器规则学习小结
关于wireshark的过滤器规则学习小结 [前言] 这两天一直在熟悉wireshark的过滤器语法规则,以前也接触过这个工具,但只是学校老师教的如何去选择一个接口进行抓取,以及如何去分析一个包的数据 ...
- Java基础---Java 数组
数组概念: 数组就是存储数据长度固定的容器,保证多个数据的数据类型要一致. 数组的定义 格式:数组定义格式详解: 数组存储的数据类型: 创建的数组容器可以存储什么数据类型. [] : 表示数组. 数组 ...