一、题目描述
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
二、思路分析
每位逐一运算,有点类似「大数运算」,不过大数运算一般都是用数组操作,这里是逆序链表操作,其实逆序链表还简单些,因为直接从个位往上加就行了,相当于两个数字尾部对齐了,若是正序链表,那还得先找到个位或者把链表反转才行。
本题的解题思路有两种:递归与非递归。下面逐一分析。
需要注意的重点有:
- 进位问题
- 两数长度错位问题
- 两数指针末尾判断
三、解决方案
方法一:递归法
从个位开始,两数相加当前位,然后除10余数即为新链表的值,进位交给下一层递归。直到没有进位并且两数都没有下一级指针为止。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
return addNumbers(l1, l2, 0);
}
//carry 为进位
public ListNode addNumbers(ListNode l1, ListNode l2, int carry) {
if(l1 != null){
carry += l1.val;
l1 = l1.next;
}
if(l2 != null){
carry += l2.val;
l2 = l2.next;
}
ListNode res = new ListNode(carry % 10);;
if(l1 != null || l2 != null || carry >=10){
res.next = addNumbers(l1, l2, carry/10);
}
return res;
}
}
- 时间复杂度: O(max(m,n)) O ( m a x ( m , n ) ) ,m和n分别代表l1和l2的长度,递归层级最深为 max(m,n) m a x ( m , n ) 层
- 空间复杂度:
O(max(m,n))
O
(
m
a
x
(
m
,
n
)
)
,由于每层递归没有开辟新的空间,而是用的l1和l2的引用,所以辅助空间可以看做常数。
递归算法的空间复杂度:递归深度n*每次递归所需的辅助空间,如果每次递归所需的辅助空间为常数,则递归空间复杂度为 O(n) O ( n ) 。
方法二:非递归法
用while循环,注意进位、长度错位、空指针等问题即可。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode res = new ListNode(0);
ListNode point = res;
int sum = 0;
while(l1 != null || l2 != null || sum > 0){
sum += (l1==null?0:l1.val) + (l2==null?0:l2.val);
point.next = new ListNode(sum % 10);
point = point.next;
if(l1!=null){
l1 = l1.next;
}
if(l2!=null){
l2 = l2.next;
}
sum /= 10;
}
return res.next;
}
}
- 时间复杂度: O(n) O ( n )
- 空间复杂度: O(n) O ( n )