单链表的大数加法

两个链表生成相加链表

http://www.nowcoder.com/questionTerminal/c56f6c70fb3f4849bc56e33ff2a50b6b

题目:给出两个非空的链表,来表示两个非负的整数。其中,它们各自的位数是按照逆序的方式存储的,并且每个结点只能存储一位数字。将这两个链表相加起来,返回一个新的链表,表示他们之和;

方法1:链表逆序后转成数字,加完后还原成链表(越界)
方法2:单链表加法

  • 链表的每一个结点存储一位数字,并且是基于自然数字逆序存储,也就是链头到链尾保持低到高位的顺序,这样就等于,进位的方向和单链表的方向一致。

  • 由于单链表的特性,没有前驱结点,无法回头。在这道题的场景下,就只需要一次 while 循环,从链头(低位)一直处理到链尾(高位),就可以解决。但是需要注意处理进位的情况,每一位结点在计算之后,需要按 10 取余数,进行存储,多的需要进位到下一结点参与运算,正好这也符合单链表的处理思路。

  • 那么我们就需要几个变量,一个 carry 用来记录每一位运算后的进位,还需要一个 dummy 结点,用于记录两个链表加法运算后的链表结点。

  • 当我们处理到最长链表最后一个结点时,还需要对 carry(进位) 进行额外的处理,如果 carry 不为 0,表示继续向高位进位,需要额外在创建一个新的结点存储进位。
    图片说明

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    // 计算结果存储的 dummy 结点
    ListNode dummy = new ListNode(0);
    ListNode p = l1, q = l2, curr = dummy;
    // 进位默认为 0
    int carry = 0;
    // 进入循环,以p和q两个链表指针都走到头为结束
    while (p != null || q != null) {
    int x = (p != null) ? p.val : 0;
    int y = (q != null) ? q.val : 0;
    // 进位参与运算
    int sum = carry + x + y;
    // 计算进位
    carry = sum / 10;
    // 构造新的结点存储计算后的位数数值
    curr.next = new ListNode(sum % 10);
    curr = curr.next;
    if (p != null) 
    p = p.next;
    if (q != null) 
    q = q.next;
    }
    // 处理数字最高位末尾进位情况
    if (carry > 0) {
    curr.next = new ListNode(carry);
    }
    return dummy.next;
    }

    这里用 p 和 q 分别存储了 l1 和 l2 两个链表的结点,以此为循环依据。循环跳出的条件为两个链表都走到了末尾。每一次循环中,处理每一位结点数数值并加上进位 carry 的值,运算后将数值取余存入新的结点,并将新的进位数存入 carry 进行存储。最后需要注意,当两个链表都处理完成之后,还需要判断最高位是否需要进位(carry > 0)。如果需要,创建一个新的链表结点存储进位值。
    扩展(链表正序):
    将两个链表逆序,这样就可以依次得到从低到高位的数字
    同步遍历两个逆序后链表,相加生成新链表,同时关注进位
    当两个链表都遍历完成后,关注进位。
    将两个逆序的链表再逆序一遍,调整回去

    public ListNode addInList (ListNode head1, ListNode head2) {
      // write code here
    
      head1=reverse(head1);
      head2=reverse(head2);
      ListNode dummy=new ListNode(-1);
    
      ListNode p=head1;
      ListNode q=head2;
      ListNode cur=dummy;
      int carry=0;
      while(p!=null || q!=null){
          int x= (p!=null)? p.val : 0;
          int y= (q!=null)? q.val: 0 ;
          int sum=x+y+carry;
          cur.next=new ListNode(sum%10);
          carry=sum/10;
          cur=cur.next;
    
          if(p!=null){
              p=p.next;
          }
          if(q!=null){
              q=q.next;
          }
      }
      if(carry>0){
          cur.next=new ListNode(carry);
      }
      return reverse(dummy.next);
    }
    //链表反转
    public ListNode reverse(ListNode head){
      ListNode cur=head;
      ListNode pre=null;
      while(cur!=null){
          ListNode tmp=cur.next;
          cur.next=pre;
          pre=cur;
          cur=tmp;
      }
      return pre;
    }
名企高频面试算法题解 文章被收录于专栏

牛客题霸 - 程序员面试高频题 - 题解

全部评论

相关推荐

不愿透露姓名的神秘牛友
11-27 10:48
点赞 评论 收藏
分享
已老实求offer😫:有点像徐坤(没有冒犯的意思哈)
点赞 评论 收藏
分享
10-07 20:48
门头沟学院 Java
听说改名就会有offer:可能是实习上着班想到后面还要回学校给导师做牛马,看着身边都是21-25的年纪,突然emo了了
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务