LeetCode :2.两数相加 解题报告及算法优化思路
题目连接:2.两数相加
题意
题目难度标为 中等, 因为题意上有一部分理解难度,以及需要数据结构的链表基础。
还不知道到链表的童鞋可以粗略的看下百度百科或者是翻出数据结构的书看一看,通俗一点的语言来解释链表就是:上线和下线。
上线知道自己的下线,但不知道自己下线的下线,同时也不知道自己的上线是谁。
这就是单向链表。
这道题的题意就是将两个数字变成了两个单向链表,其中每一个节点存储一位数字,且是逆序存放,也就是倒过来存了。
解题思路
首先来想一下不同情况和对应的案例:
- 两个链表长度相等。
输入:(2 -> 4 -> 3) + (5 ->6 -> 4)
输出:(7 -> 0 -> 8)
- 两个链表长度不等。
输入:(2 -> 4) + (5 -> 6 -> 4)
输出:(7 -> 0 -> 5)
- 最终结果的最高位存在进位的情况。
输入:(2 -> 4 -> 5) + (5 -> 6 -> 4)
输出:(7 -> 0 -> 0 -> 1)
解题的关键便是:合并链表并且保证进位正确。
模拟进位
首先我们按位相加,然后再对每一位进行进位处理,满 10 则进 1。
代码:
public class Solution
{
public ListNode AddTwoNumbers(ListNode l1, ListNode l2)
{
ListNode first = null;
ListNode current = null;
IList<int> sums = new List<int>();
int sum = 0;
int res = 0;
while (l1 != null || l2 != null)
{
sum = res;
if (l1 != null)
{
sum += l1.val;
l1 = l1.next;
}
if (l2 != null)
{
sum += l2.val;
l2 = l2.next;
}
res = sum / 10;
sum %= 10;
sums.Add(sum);
}
if(res > 0) sums.Add(res);
if(sums.Any()) first = new ListNode(sums[0]);
current = first;
for (int i = 1; i < sums.Count; i++)
{
current.next = new ListNode(sums[i]);
current = current.next;
}
return first;
}
}
执行用时: 252 ms, 在所有 C# 提交中击败了13.33%的用户
内存消耗: 26.7 MB
这个耗时有点凄惨,接近垫底了。那也说明了还有很大的优化空间。
优化常量
上面我们在循环时使用到了 IList 的 Count,这里我们可以提前将其存储起来。
代码如下:
public class Solution
{
public ListNode AddTwoNumbers(ListNode l1, ListNode l2)
{
ListNode first = null;
ListNode current = null;
IList<int> sums = new List<int>();
int sum = 0;
int res = 0;
int count = 0;
while (l1 != null || l2 != null)
{
sum = res;
if (l1 != null)
{
sum += l1.val;
l1 = l1.next;
}
if (l2 != null)
{
sum += l2.val;
l2 = l2.next;
}
res = sum / 10;
sum %= 10;
sums.Add(sum);
}
if (res > 0) sums.Add(res);
count = sums.Count;
if (count > 0) first = new ListNode(sums[0]);
current = first;
for (int i = 1; i < count; i++)
{
current.next = new ListNode(sums[i]);
current = current.next;
}
return first;
}
}
执行用时: 164 ms, 在所有 C# 提交中击败了85.62%的用户
内存消耗: 26.8 MB
仅仅是替换了一个变量,执行用时就优化了近 100ms! 这 100ms 就超过了 70% 的提交。
前面还有近 15% 说明还有优化空间。
优化循环数
上面的算法,如果按照大O表示法来计算复杂度的话,它的复杂度是:O(max(l1.Length, l2.Length)) ,再精简一下也就是 O(n),即单重循环的程度。
但真正的复杂度是(同样也是估算,循环内的操作数没有算进来,这里只算了循环的):2 * max(l1.Length, l2.Length) + 1。因为这里实际上是使用了两个循环。那么我们可以将这个复杂度表达式中的倍数 : 2 去掉,即只用一重循环。
代码如下:
public class Solution
{
public ListNode AddTwoNumbers(ListNode l1, ListNode l2)
{
ListNode first = null;
ListNode current = null;
int sum = 0;
int res = 0;
while (l1 != null || l2 != null)
{
sum = res;
if (l1 != null)
{
sum += l1.val;
l1 = l1.next;
}
if (l2 != null)
{
sum += l2.val;
l2 = l2.next;
}
res = sum / 10;
sum %= 10;
if (current == null)
{
first = new ListNode(sum);
current = first;
}
else
{
current.next = new ListNode(sum);
current = current.next;
}
}
if (res > 0) current.next = new ListNode(res);
return first;
}
}
执行用时: 136 ms, 在所有 C# 提交中击败了98.85%的用户
内存消耗: 26.5 MB
在我们移除掉一重循环之后,执行用时优化了 20 多ms(为什么不是优化了近一半的时间?),而这 20 多ms就又超过了 13% 的提交。
对于Leetcode判题耗时的思考
处于对连续两道题目都没有办法达到最优(至少前 1% )的情况下,若羽今天写到这里时,特意去看了一下耗时最短的代码(104ms),复制下来之后直接提交,结果显示是 248ms !??
再次提交之后结果显示是 160 ms !??
同一份代码, 上下浮动的区间未免也太大了!若羽不禁思考起 LeetCode 的判题核心是如何进行计时的。这个浮动区间已经达到可以破坏排名公平性的程度了,也许有人会觉得若羽危言耸听,夸大其词。
事实是:确实已经达到破坏公平的程度了!!!,这一类在线运行代码并且自动输入案例比对结果的系统其实很早就已经出现,在 信息学竞赛 以及 ACM大学生程序设计竞赛 中通常被称为 OJ(Online Judge System) 在线判题系统。而在竞赛场上,差距达到 160ms 意味着什么?意味着两队选手同时甚至略迟一点点提交代码,最终谁的排名在前还得听天命。
抛开竞赛的立场,浮动如此大的排名,在一定程度上已经无法再客观的去评价时间复杂度相近算法的优劣了。排名第一的算法再运行一次也有可能会排到末尾去。
但是算法优化的思路还是可以继续,撸码不停,优化不止~(好想自己实现一个 OJ 了!)
LeetCode :2.两数相加 解题报告及算法优化思路的更多相关文章
- LeetCode :1.两数之和 解题报告及算法优化思路
最近开始重拾算法,在 LeetCode上刷题.顺便也记录下解题报告以及优化思路. 题目链接:1.两数之和 题意 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 ...
- leetcode之两数相加解题思路
问题描述 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,数组中同一个元素不能使 ...
- Leetcode 002. 两数相加
1.题目描述 给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表 ...
- LeetCode 445——两数相加 II
1. 题目 2. 解答 2.1 方法一 在 LeetCode 206--反转链表 和 LeetCode 2--两数相加 的基础上,先对两个链表进行反转,然后求出和后再进行反转即可. /** * Def ...
- Leetcode 445. 两数相加 II
1.题目描述 给定两个非空链表来代表两个非负整数.数字最高位位于链表开始位置.它们的每个节点只存储单个数字.将这两数相加会返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. ...
- LeetCode 445. 两数相加 II(Add Two Numbers II)
445. 两数相加 II 445. Add Two Numbers II 题目描述 给定两个非空链表来代表两个非负整数.数字最高位位于链表开始位置.它们的每个节点只存储单个数字.将这两数相加会返回一个 ...
- LeetCode 2. 两数相加(Add Two Numbers)
2. 两数相加 2. Add Two Numbers 题目描述 You are given two non-empty linked lists representing two non-negati ...
- LeetCode 2——两数相加(JAVA)
给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和 ...
- LeetCode 2. 两数相加(Add Two Numbers)
题目描述 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入: ...
随机推荐
- Effective Java - 构造器私有、枚举和单例
目录 饿汉式单例 静态常量 静态代码块 懒汉式单例 尝试加锁 同步代码块 双重检查 静态内部类单例 枚举单例 Singleton 是指仅仅被实例化一次的类.Singleton代表了无状态的对象像是方法 ...
- 2018.8.19 2018暑假集训之maxnum
昨天去做志愿服务去了没写成Q_Q 今天再来一道 先放题面描述 设有n个正整数(n<=20),将它们联成一排,组成一个最大的多位数 设有n个正整数(n<=20),将它们联成一排,组成一个最大 ...
- 深入理解Java的switch...case...语句
switch...case...中条件表达式的演进 最早时,只支持int.char.byte.short这样的整型的基本类型或对应的包装类型Integer.Character.Byte.Short常量 ...
- kuangbin专题 专题一 简单搜索 Shuffle'm Up POJ - 3087
题意:(1)有两副颜色多样的扑克牌,(A~H)表示不同颜色,给你两副牌,S1,S2和一副你需要洗出的KEY,S12由S2最底部,S1底部...一直下去,直到洗成S12,就是图片展示的那样.(2)洗好的 ...
- 音频编辑器 OcenAudio v3.1.9.0 绿色便携版
下载地址:点我 基本介绍 ocenaudio是一款跨平台的,易于使用的,快速的,功能强大的,好用的音频编辑软件.该软件支持Virtual Studio Technology插件,美观.统一的跨平台界面 ...
- SpringCloud解析之Eureka
本文基于Spring Cloud Edgware.SR6版本,从功能和架构上解析Eureka,让大家对Eureka有一个较为清晰的认识(本文默认大家对分布式微服务有一个初步的概念和理解,本文不涉及或少 ...
- Docker笔记(四):Docker镜像管理
原文地址:http://blog.jboost.cn/2019/07/16/docker-4.html 在Docker中,应用是通过容器来运行的,而容器的运行是基于镜像的,类似面向对象设计中类与对象的 ...
- k8s学习 - 概念 - Deployment
k8s学习 - 概念 - Deployment 有了 ReplicaSet 还需要有 Deployment 的原因是希望有一个控制器能管理部署更新时候的版本控制问题.一个 Deployment 可以管 ...
- 【DFS练习】【最大的蛋糕块】-C++
这道题目是一个基本的dfs模板(?)下面日常贴一波dfs的基本模板: void dfs()//参数用来表示状态 { if(到达终点状态) { ...//根据题意添加 return; } if(越界或者 ...
- python+selenium 批量执行时出现随机报错问题【已解决】
出现场景:用discover方法批量执行py文件,出现随机性的报错(有时a.py报错,有时b.py报错...),共同特点:均是打开新窗口后,切换最新窗口,但定位不到新窗口的元素,超时报错.由于个人项目 ...