[不定时一题]LeetCode两数相加

时间:2022-07-25
本文章向大家介绍[不定时一题]LeetCode两数相加,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

LeetCode第二天

今天又是充满希望的一天,勇士准备好了吗? ”

早晨起床第一步,打开电脑LeetCode,今天给大家带来的是LeetCode的第二题两数相加:

首先看看题目难度中等,接着几个特殊的关键字出现在眼帘,非空,逆序,一位这几个关键字顾名思义很容易理解,但是题目中有两个字链表顿时一脸懵。

什么是链表?

链表[1]是一种动态的数据结构,不同于数组的是,链表分配内存空间的灵活性,它不会像数组一样被分配一块连续的内存。当你想在数组的任意位置,插入一个新值的时候,必须对数组中的各个元素进行相应的位置移动才能达到目标,开销显然是很大的。然而链表的灵活性在于它的每个元素节点分为两部分,一部分是存储元素本身,另一部分是指向下一个节点元素的引用,也可以称为指针,当你要插入数据时,把上一个节点的向下指针指向新数据节点,新数据节点的向下指针指向原有数据。但是链表不像数组那样可以直接通过索引立刻定位,只能通过遍历。

链表和数组的区别

不同:

  • 链表是链式的存储结构;数组是顺序的存储结构。
  • 链表通过指针来连接元素与元素,数组则是把所有元素按次序依次存储。

还有一个比较形象的图片

更多的关于链表的知识详见链表如此简单[2]单向链表[3]两篇文章

言归正传,首先分析题目,我们画一个简单的图形:

l1l2的每一个节点相加的和得到一个新的数,组合成一个新的链表,如果相加的和大于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]的临界点(边界值),对l1l2非空判断的不够完善

/**
 * 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()val0

・・・下期再见・・・

最后

本文结束,有什么问题和有错误的地方,欢迎大家的留言和评论,还有后续更新,下期更加精彩 ??? ”

参考资料

[1]

链表: https://www.cnblogs.com/tdws/p/6033209.html

[2]

链表如此简单: https://juejin.im/post/6844904118708879367#heading-19

[3]

单向链表: https://juejin.im/post/6844903857508597774