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 之外,这两个数字都不会以零开头. 示例: 输入: ...
随机推荐
- Nginx Location匹配顺序
理论部分 文字释义匹配规则如下: 略述: 1.nginx服务器首先在server块的多个location块中搜索是否有标准的uri和请求字符串匹配.如果有多个标准uri可以匹配,就匹配其中匹配度最高的 ...
- Oracle数据库---PLSQL
SET SERVEROUTPUT ONBEGIN --打印输出 DBMS_OUTPUT.PUT_LINE('hello everyone!');END; DECLARE v_name VARCHAR2 ...
- c++ 广度优先搜索(宽搜)
c++ bfs基本应用 Knight Moves 题目描述 贝茜和她的表妹在玩一个简化版的国际象棋.棋盘如图所示: 贝茜和表妹各有一颗棋子.棋子每次移一步,且棋子只能往如图所示的八个方向移动.比赛的规 ...
- Noip 2016 愤怒的小鸟 题解
[NOIP2016]愤怒的小鸟 时间限制:1 s 内存限制:256 MB [题目描述] Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0, ...
- 这样子来理解C语言中指针的指针
友情提示:阅读本文前,请先参考我的之前的文章<从四个属性的角度来理解C语言的指针也许会更好理解>,若已阅读,请继续往下看. 我从4个属性的角度来总结了C语言中的指针概念.对于C语言的一个指 ...
- [Spring+SpringMVC+Mybatis]框架学习笔记(六):事务
第7讲 事务 7.1 事务的概念 事务是一系列作为一个逻辑单元来执行的操作集合. 它是数据库维护数据一致性的单位,它讲数据库从一个一致状态,转变为新的另外一个一致状态.说的简单一点就是:如果一组处理步 ...
- [记录]Python高并发编程
========== ==多进程== ========== 要让Python程序实现多进程(multiprocessing),我们先了解操作系统的相关知识. Unix/Linux操作系统提供了一个fo ...
- [转载]linux下清除Squid缓存的方法记录
在日常运维工作中,只要用到squid缓存服务,就会常常被要求清理squid缓存. 比如公司领导要求删一篇新闻,新闻是生成的静态.运维人员把服务器上静态的新闻页面删除了后,不料代理服务器上缓存还有.缓存 ...
- vbox 设置时间不与主机同步
C:\Users\2345-lp0395>"D:\Program Files\Oracle\VirtualBox\VBoxManage.exe" setexadata win ...
- Ubuntu系统安装QQ等软件
1.安装deepin-wine环境:上https://github.com/wszqkzqk/deepin-wine-for-ubuntu页面下载zip包(或用git方式克隆),解压到本地文件夹,在文 ...