[不定时一题]LeetCode两数相加
LeetCode第二天
今天又是充满希望的一天,勇士准备好了吗? ”
早晨起床第一步,打开电脑LeetCode
,今天给大家带来的是LeetCode
的第二题两数相加
:
首先看看题目难度中等
,接着几个特殊的关键字出现在眼帘,非空
,逆序
,一位
这几个关键字顾名思义很容易理解,但是题目中有两个字链表
顿时一脸懵。
什么是链表?
链表[1]是一种动态的数据结构,不同于数组的是,链表分配内存空间的灵活性,它不会像数组一样被分配一块连续的内存。当你想在数组的任意位置,插入一个新值的时候,必须对数组中的各个元素进行相应的位置移动才能达到目标,开销显然是很大的。然而链表的灵活性在于它的每个元素节点分为两部分,一部分是存储元素本身,另一部分是指向下一个节点元素的引用,也可以称为指针,当你要插入数据时,把上一个节点的向下指针指向新数据节点,新数据节点的向下指针指向原有数据。但是链表不像数组那样可以直接通过索引立刻定位,只能通过遍历。
链表和数组的区别
不同:
- 链表是链式的存储结构;数组是顺序的存储结构。
- 链表通过指针来连接元素与元素,数组则是把所有元素按次序依次存储。
还有一个比较形象的图片
更多的关于链表的知识详见链表如此简单[2]和单向链表[3]两篇文章
言归正传,首先分析题目,我们画一个简单的图形:
l1
和l2
的每一个节点相加的和得到一个新的数,组合成一个新的链表,如果相加的和大于10的倍数上后一位对应的进位。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
//新建初始化结果链表
var result = new ListNode("head");
//初始化进位
var carry = 0;
//链表相加的初始值
var resVal = null;
while(l1||l2){ //判断非空链表
resVal= l1.val+l2.val+carry;
carry = parseInt(resVal/10); //获取进位数组
result.next =new ListNode(resVal%10); //相加后的结果
result = result.next //给结果链表赋值继续往下走
l1= l1.next; //l1.val结束之后把l1.next重新赋值给l1
l2= l2.next; //l2.val结束之后把l1.next重新赋值给l2
console.log(result)
}
return result
};
执行的结果出现问题,result
只有最后一项,再看控制台输出stdout
:每次遍历的result
都是有值的,而且和结果一样,但是输出的却不对,问题就出现在了 result = result.next
这句话上,每次遍历的时候result
都重新赋值,把原来定义的result
覆盖了。我们可以在初始化result
的时候,声明一个新的res
变量作为result
的替死鬼,每次重新赋值res
,但是result
作为爸爸,会目睹res发生的一切变化,然后记录下来。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
//新建初始化结果链表
var result = new ListNode("head");
var res = result;
//初始化进位
var carry = 0;
//链表相加的初始值
var resVal = null;
while(l1||l2){ //判断非空链表
resVal= l1.val+l2.val+carry;
carry = parseInt(resVal/10); //获取进位数组
res.next =new ListNode(resVal%10); //相加后的结果
res = res.next //给结果链表赋值继续往下走
l1= l1.next; //l1.val结束之后把l1.next重新赋值给l1
l2= l2.next; //l2.val结束之后把l1.next重新赋值给l2
console.log(result)
}
return result
}
是不是看到了希望返回了[NaN,7,0,8]
,通过stdout
是不是看到了result
记录着res
做的一切坏事,哈哈。到了这里我们不要NaN
,那我们的结果return result.next
即可
但是提交之后的结果,果然不会让我失望
我们没有考虑特殊的临界值,这个很重要
第一种情况:
l1
为[5],l2
为[5],也就是两个链表都只有一个节点,而且相加之后有进位
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
//新建初始化结果链表
var result = new ListNode("head");
var res = result;
//初始化进位
var carry = 0;
//链表相加的初始值
var resVal = null;
while(l1||l2){ //判断非空链表
resVal= l1.val+l2.val+carry;
carry = parseInt(resVal/10); //获取进位数组
res.next =new ListNode(resVal%10); //相加后的结果
res = res.next //给结果链表赋值继续往下走
l1= l1.next; //l1.val结束之后把l1.next重新赋值给l1
l2= l2.next; //l2.val结束之后把l1.next重新赋值给l2
console.log(result)
}
if((l1==null||l2==null)&&carry){
res.next = new ListNode(1)
}
return result.next
}
看起来很美,但是再次执行的时候,就问你惊喜不惊喜
第二种情况:
l1
为[1,8],l2
为[0]的临界点(边界值),对l1
和l2
非空判断的不够完善
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function(l1, l2) {
//新建初始化结果链表
var result = new ListNode("head");
var res = result;
//初始化进位
var carry = 0;
//链表相加的初始值
var resVal = null;
while(l1||l2){ //判断非空链表
if(!l1) l1 = new ListNode();
if(!l2) l2 = new ListNode();
resVal= l1.val+l2.val+carry;
carry = parseInt(resVal/10); //获取进位数组
res.next =new ListNode(resVal%10); //相加后的结果
res = res.next //给结果链表赋值继续往下走
l1= l1.next; //l1.val结束之后把l1.next重新赋值给l1
l2= l2.next; //l2.val结束之后把l1.next重新赋值给l2
}
if((l1==null||l2==null)&&carry){
res.next = new ListNode(1)
}
return result.next
}
在这里新创建new ListNode()
的val
是0
・・・下期再见・・・
最后
本文结束,有什么问题和有错误的地方,欢迎大家的留言和评论,还有后续更新,下期更加精彩 ??? ”
参考资料
[1]
链表: https://www.cnblogs.com/tdws/p/6033209.html
[2]
链表如此简单: https://juejin.im/post/6844904118708879367#heading-19
[3]
单向链表: https://juejin.im/post/6844903857508597774
- hdu----(1466)计算直线的交点数(dp)
- golang模板template自定义函数用法示例
- 程序员你为什么这么累【续】:编写简陋的接口调用框架 - 动态代理学习
- hdu---(Tell me the area)(几何/三角形面积以及圆面积的一些知识)
- MySQL数据库(六):体系结构和存储引擎
- hdu----(2222)Keywords Search(trie树)
- MySQL数据库(七):数据导出与导入
- flume与kafka整合高可靠教程
- Oracle 12c系列(一)|多租户容器数据库
- Spring Security入门(三):密码加密
- MySQL数据库(八):表记录的基本操作(增删改查)
- flume应该思考的问题
- 利用Go语言实现简单Ping过程的方法
- MySQL数据库(九):修改表结构
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 3分钟短文:Laravel 模型一对一关联关系这俩啥区别
- Day46:孩子们的游戏(圆圈中最后剩下的数)
- 3分钟短文:Laravel 检查记录是否被软删除
- Day47:求1+2+3+……+n
- 3分钟短文:Laravel 使用DB门面操作原生SQL
- Day48:不用加减乘除做加法
- Day49:将字符串转换成整数
- Day50:数组中重复的数字
- 3分钟短文:Laravel模型OR查询避坑指南
- Day51:构建乘积数组
- 3分钟短文:Laravel ORM 模型用法纲要
- Day52:正则表达式匹配
- 3分钟短文:Laravel 模型查询数据库的几个关键方法
- Day53:表示数值的字符串
- 3分钟短文:Laravel模型写操作很简单,大多数人容易用错