2_两数相加
描述
给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
解法:小学数学
思路
这道题的求解思路和在纸上求两数之和一样,从最低位(链表表头)开始,逐位(节点)求和,用变量 carry
保存前一位的进位结果,如果求和的过程到达长度较短的链表的尾部(空节点 null
),则求和时将该节点的值当作 0,求和结束后还需要判断 carry
变量的值是否为 1,如果为 1 还需要添加一个节点(节点取值为 1)作为最高位。具体的求解过程如下图所示:
非递归实现
Java 实现(非递归写法 1)
/**
* 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) {
ListNode dummyHead = new ListNode(-1);
ListNode curNode = dummyHead, p = l1, q = l2;
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;
carry = sum / 10;
curNode.next = new ListNode(sum % 10);
curNode = curNode.next;
if (p != null) {
p = p.next;
}
if (q != null) {
q = q.next;
}
}
if (carry > 0) {
curNode.next = new ListNode(carry);
}
return dummyHead.next;
}
}
复杂度分析:
- 时间复杂度: O ( m a x ( m , n ) ) O(max(m, n)) O(max(m,n)),其中 m m m 和 n n n 分别表示两个链表的长度
- 空间复杂度: O ( m a x ( m , n ) ) O(max(m, n)) O(max(m,n)),返回链表的长度最多为 m a x ( m , n ) + 1 max(m, n) + 1 max(m,n)+1
Java 实现(非递归写法 2)★
/**
* 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) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
int carry = 0;
for (ListNode p1 = l1, p2 = l2; p1 != null || p2 != null; ) {
int sum = carry;
sum += (p1 != null) ? p1.val : 0;
sum += (p2 != null) ? p2.val : 0;
tail.next = new ListNode(sum % 10);
tail = tail.next;
carry = sum / 10;
p1 = (p1 == null) ? p1 : p1.next;
p2 = (p2 == null) ? p2 : p2.next;
}
if (carry != 0) {
tail.next = new ListNode(carry);
}
return dummy.next;
}
}
复杂度分析同上。
Python 实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
dummy_head = ListNode(-1)
cur = dummy_head
carry = 0
while l1 or l2 or carry:
v1 = v2 = 0
if l1:
v1 = l1.val
l1 = l1.next
if l2:
v2 = l2.val
l2 = l2.next
carry, val = divmod(v1 + v2 + carry, 10)
cur.next = ListNode(val)
cur = cur.next
return dummy_head.next
复杂度分析同上。
递归实现
Java 实现
/**
* 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 addTwoNumbers(l1, l2, 0);
}
private ListNode addTwoNumbers(ListNode l1, ListNode l2, int carry) {
// Recursive termination condition
if (l1 == null && l2 == null) {
return carry > 0 ? new ListNode(carry) : null;
}
int sum = carry;
ListNode l1Next = null, l2Next = null;
if (l1 != null) {
sum += l1.val;
l1Next = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2Next = l2.next;
}
ListNode curr = new ListNode(sum % 10);
curr.next = addTwoNumbers(l1Next, l2Next, sum / 10);
return curr;
}
}
复杂度分析:
- 时间复杂度: O ( m a x ( m , n ) ) O(max(m, n)) O(max(m,n)),其中 m m m 和 n n n 分别表示两个链表的长度
- 空间复杂度: O ( m a x ( m , n ) ) O(max(m, n)) O(max(m,n)),额外空间是由于递归调用占用系统栈的空间,递归的深度最多为 m a x ( m , n ) + 1 max(m, n) + 1 max(m,n)+1 层
Python 实现
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
def helper(l1, l2, carry):
if not l1 and not l2:
if carry > 0:
return ListNode(carry)
else:
return None
sum = carry
l1_next, l2_next = None, None
if l1:
sum += l1.val
l1_next = l1.next
if l2:
sum += l2.val
l2_next = l2.next
curr = ListNode(sum % 10)
curr.next = helper(l1_next, l2_next, sum // 10)
return curr
return helper(l1, l2, 0)
复杂度分析同上。