leetcode-2. 两数相加

162 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

  1. 两数相加

题目

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.

示例 2:

输入:l1 = [0], l2 = [0] 输出:[0]

示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9] 输出:[8,9,9,9,0,0,0,1]

提示:

每个链表中的节点数在范围 [1, 100]0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零

数字转换

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
 import java.math.BigInteger;
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
            StringBuffer s1 = new StringBuffer();
        while (l1!=null){
            s1.append(l1.val);
            l1=l1.next;
        }

        StringBuilder s2 = new StringBuilder();
        while (l2!=null){
            s2.append(l2.val);
            l2=l2.next;
        }
        BigInteger i = new BigInteger(s1.reverse().toString()).add(new BigInteger(s2.reverse().toString()));
        String s = new StringBuffer().append(i).reverse().toString();
        ListNode head=null;
        ListNode temp = null;
        for (int i1 = 0; i1 < s.length(); i1++) {
            if (i1==0){
                temp=head= new ListNode(Integer.parseInt(String.valueOf(s.charAt(i1))));
            }else {
                temp.next= new ListNode(Integer.parseInt(String.valueOf(s.charAt(i1))));
                temp=temp.next;
            }
        }
        return head;
    }
}


首先获取链表l1和l2的所有node的val,添加到StringBuffer,应该用StringBuilder的,StringBuilder比StringBuffer性能更好,在非多线程情况下更有优势。

BigInteger i = new BigInteger(s1.reverse().toString()).add(new BigInteger(s2.reverse().toString()));
String s = new StringBuffer().append(i).reverse().toString();

核心部分,将字符串reverse输出并通过BigInteger相加得到结果,然后利用StringBuffer将得到的结果i再次进行字符串reverse。

最后通过循环取出字符串中的字符,放入单向链表中。😀

进位法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode head=null,tail=null;
        int carry=0;
        while(l1!=null||l2!=null){
           int n1 = l1!=null?l1.val:0;
           int n2 = l2!=null?l2.val:0;
           int sum=n1+n2+carry;
           if(head==null){
               head=tail=new ListNode(sum%10);
           }else{
               tail.next=new ListNode(sum%10);
                tail=tail.next;
           }
            carry=sum/10;
            if(l1!=null){
                l1=l1.next;
            }
            if(l2!=null){
                l2=l2.next;
            }
        }
        if(carry>0){
            tail.next=new ListNode(carry);
        }
        return head;
    }
}

过程式语言对每个执行步骤的顺序是有严格的控制的。

接下来我会对每个步骤进行讲解。

 while(l1!=null||l2!=null)

循环条件是addTwoNumbers的两个参数不为空,注意这里是短路或!

           int n1 = l1!=null?l1.val:0;
           int n2 = l2!=null?l2.val:0;
           int sum=n1+n2+carry;

这是什么鬼?循环条件是不为空,若为空就进入不了循环了。这里为什么还要判断不为空,很多人看这里会有点懵,这么说吧,若是两个参数给的链表长度不一样会怎么样?所以这里三目运算符的作用就是为了填补链表长度不够的问题。举个例子l1是a->b->c,l2是a->b,但是l2长度是2,所有要在l2后面虚拟一个c值为0。

n1+n2+carry。这里加上了进位。例如:n1=9,n2=9.carry=1。

           if(head==null){
               head=tail=new ListNode(sum%10);
           }else{
               tail.next=new ListNode(sum%10);
                tail=tail.next;
           }

这段代码主要是链表上的Node的添加,sum%10要搞懂,此处求模的意思是求个位数,

carry=sum/10;

求进位,10的进位是1,20的进位是2,28的进位还是2,所以逆推下carry的类型是int!28/10=2.0,int类型会得到2。

但是这题carry永远都是1,题目限制了0 <= Node.val <= 9,最大值是9+9=18。

第一次n1=9,n2=9,carry=0,sum=n1+n2+carry=18,Node.val=sum%10=18%10=8。

第二次n1=9,n2=9,carry=1,sum=19,Node.val=sum%10=9。

第一次是个位,第二次是十位,合起来就是98。

            if(l1!=null){
                l1=l1.next;
            }
            if(l2!=null){
                l2=l2.next;
            }

获取链表的下一个Node。

        if(carry>0){
            tail.next=new ListNode(carry);
        }

第一次,n1=2,n2=5,carry=0,各位为7。

第二次,n1=4,n2=6,carry=1,个位为0。

合起来是07,😈,那第二次的carry就消失了,这句的作用就是补最后的carry,当然carry等于0没必要加了。

正确答案是107。

总结

进位法是我写的第一个,☺有天突发奇想写了个数字转换,但是性能太拉了差了8倍。虽然算法要求的是性能,但是这次我感受到不同思维实现算法的快乐,管他呢快乐万岁!

还没完,有空更新Stream法。