给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。

 

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

 

示例:

输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7

结点类如下

1public class ListNode {
2    int val;
3    ListNode next;
4
5    ListNode(int x) {
6        val = x;
7    }
8}

答案:

 1public ListNode addTwoNumbers(ListNode list1, ListNode list2) {
2    Stack<Integer> s1 = new Stack<>();
3    Stack<Integer> s2 = new Stack<>();
4    while (list1 != null) {
5        s1.push(list1.val);
6        list1 = list1.next;
7    }
8    while (list2 != null) {
9        s2.push(list2.val);
10        list2 = list2.next;
11    }
12    int sum = 0;
13    ListNode head = new ListNode(0);
14    while (!s1.empty() || !s2.empty()) {
15        if (!s1.empty())
16            sum += s1.pop();
17        if (!s2.empty())
18            sum += s2.pop();
19        head.val = sum % 10;
20        ListNode node = new ListNode(sum / 10);
21        node.next = head;
22        head = node;
23        sum /= 10;
24    }
25    return head.val == 0 ? head.next : head;
26}

解析:

思路其实很简单,就是分别把两个链表的结点先存放到两个栈中,因为链表的最高位是在链表的最开始的位置,所以存放到栈中之后,栈底是高位,栈顶是个位(也是低位),然后两个栈中的元素再相加,因为栈是先进后出的,最先出来的肯定是个位(也是低位),最后出来的肯定是高位,也就是这两个数是从个位开始相加,这也符合加法的运算规律。

 

1,代码中第19行我们只保存相加的个位数,因为链表的每个结点只能保存一位数,如果有进位就会在下一步进行保存。

 

2,第20行在保留进位的值。其中第20到22行涉及到链表的插入,这个使用的是头插法,在链表节点的头部插入,比较简单,如果看不懂的,还可以看下前面刚讲的352,数据结构-2,链表

 

3,代码第25行先判断链表相加之后的最高位是否有进位,如果有就直接返回,如果没有就返回头结点head的下一个结点即可。

 

代码比较简单,我们就以上面的例子来画一个图加深一下理解,

 

355,两数相加 II_编程开发

355,两数相加 II_编程开发_02

355,两数相加 II_编程开发_03

355,两数相加 II_两数相加_04

355,两数相加 II_两数相加_05

对于加法运算这块,我们还可以再来换一种写法

 1public ListNode addTwoNumbers(ListNode list1, ListNode list2) {
2    Stack<ListNode> stk1 = new Stack();
3    Stack<ListNode> stk2 = new Stack();
4    while (list1 != null) {
5        stk1.push(list1);
6        list1 = list1.next;
7    }
8    while (list2 != null) {
9        stk2.push(list2);
10        list2 = list2.next;
11    }
12    int carry = 0;
13    ListNode node = null, prev = null;
14    while (!stk1.isEmpty() || !stk2.isEmpty()) {
15        int no1 = !stk1.isEmpty() ? stk1.pop().val : 0;
16        int no2 = !stk2.isEmpty() ? stk2.pop().val : 0;
17        node = new ListNode((no1 + no2 + carry) % 10);
18        carry = (no1 + no2 + carry) / 10;
19        node.next = prev;
20        prev = node;
21    }
22    if (carry != 0) {
23        node = new ListNode(carry);
24        node.next = prev;
25    }
26    return node;
27}

carry表示的是进位的值,上面两种方式虽然写法上有一点差别,但整体思路还是没变,下面我们再来换种思路,使用递归的方式来解决

 1public ListNode addTwoNumbers(ListNode list1, ListNode list2) {
2    int size1 = getLength(list1);
3    int size2 = getLength(list2);
4    ListNode head = new ListNode(1);
5    head.next = size1 < size2 ? helper(list2, list1, size2 - size1) : helper(list1, list2, size1 - size2);
6    if (head.next.val > 9) {
7        head.next.val = head.next.val % 10;
8        return head;
9    }
10    return head.next;
11}
12
13//这里链表list1的长度是大于等于list2的长度的
14public ListNode helper(ListNode list1, ListNode list2, int offset) {
15    if (list1 == null)
16        return null;
17    ListNode result = offset == 0 ? new ListNode(list1.val + list2.val) : new ListNode(list1.val);
18    ListNode post = offset == 0 ? helper(list1.next, list2.next, 0) : helper(list1.next, list2, offset - 1);
19    if (post != null && post.val > 9) {
20        result.val += 1;
21        post.val = post.val % 10;
22    }
23    result.next = post;
24    return result;
25}
26
27public int getLength(ListNode list) {
28    int count = 0;
29    while (list != null) {
30        list = list.next;
31        count++;
32    }
33    return count;
34}

getLength表示的是计算链表的长度,代码很容易理解。这题解法思路奇特的地方在第4行,他先默认两个链表相加,最高位会有进位,然后在第6行进行判断,如果确实有进位,修改一下head.next的值,然后返回head,如果没有进位,直接在第10行返回head.next即可。这段代码的核心是在helper方法中,我们来仔细分析一下

 

1,list1的长度是大于等于list2的长度的,offset表示的是list1的长度与list2长度的差值,如果list1长度大于list2的长度,那么offset是正数,如果list1长度等于list2的长度,那么offset就是0,offset不可能是负数,因为list1长度不可能小于list2的长度。

 

2,第17行是创建一个新的结点,如果两个链表长度相等,这个新的结点的值就是这两个链表的头结点相加(注意这里的头结点是一直变的),否则新结点的值就是list1的头结点的值。

 

3,然后第18行进行这种递归的操作后续结点

 

4,19行判断后续结点是否有进位,如果有进位再处理进位的问题

 

5,第23行是链表的连接,连接之后在24行直接返回。

 

往期精彩回顾

352,数据结构-2,链表

333,奇偶链表

280,排序链表

276,重排链表

275,环形链表 II

232,旋转链表

355,两数相加 II_两数相加_06