题目描述:中等难度
就是两个链表表示的数相加,这样就可以实现两个很大的数相加了,无需考虑数值 int
,float
的限制了。
链表最左边表示个位数,代表 342 + 465 =807
思路
首先每一位相加肯定会产生进位,我们用 carry
表示。进位最大会是 1 ,因为最大的情况是无非是 9 + 9 + 1 = 19 ,也就是两个最大的数相加,再加进位,这样最大是 19 ,不会产生进位 2 。下边是伪代码。
- 初始化一个节点的头,
dummy head
,但是这个头不存储数字。并且将cur
指向它。 - 初始化进位
carry
为 0 。 - 初始化
p
和q
分别为给定的两个链表l1
和l2
的头,也就是个位。 - 循环,直到
l1
和l2
全部到达 null 。 - 设置
x
为p
节点的值,如果p
已经到达了null
,设置x
为0
。 - 设置
y
为q
节点的值,如果q
已经到达了null
,设置y
为0
。 - 设置
sum = x + y + carry
。 - 更新
carry = sum / 10
。 - 创建一个值为
sum mod 10
的节点,并将curr
的next
指向它,同时curr
指向变为当前的新节点。 - 向前移动
p
和q
。 - 判断
carry
是否等于1
,如果等于1
,在链表末尾增加一个为 1 的节点。 - 返回
dummy head
的next
,也就是个位数开始的地方。
初始化的节点 dummy head
没有存储值,最后返回 dummy head
的 next
。这样的好处是不用单独对 head
进行判断改变值。也就是如果一开始的 head
就是代表个位数,那么开始初始化的时候并不知道它的值是多少,所以还需要在进入循环前单独对它进行值的更正,不能像现在一样只用一个循环简洁。
代码如下所示:
class ListNode{
int val;
ListNode next;
ListNode(int x){val=x;}
}
public class Add_Two_Numbers {
public static ListNode addTwoNumbers(ListNode l1,ListNode l2){
ListNode dummyHead = new ListNode(0);
ListNode p = l1;
ListNode q = l2;
ListNode cur = dummyHead;
int carry = 0;
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;
cur.next=new ListNode(sum % 10);
cur=cur.next;
if(p!=null) p=p.next;
if(q!=null) q=q.next;
}
return dummyHead.next;
}
public static void main(String args[]){
ListNode l1=new ListNode(2);
ListNode p=l1;
p.next=new ListNode(4);
p=p.next;
p.next=new ListNode(3);
ListNode l2=new ListNode(5);
ListNode q=l2;
q.next=new ListNode(6);
q=q.next;
q.next=new ListNode(4);
ListNode ans = addTwoNumbers(l1,l2);
while(ans!=null){
System.out.println(ans.val);
ans=ans.next;
}
}
}
这里有一个需要注意的点就是
if (carry > 0) {
curr.next = new ListNode(carry);
}
为什么要添加这个条件:
举个例子L1=[5],L2=[5],最终cur加入的是(5+5)%10=0,还需要把1加进去。
-
时间复杂度:O(max(m,n)),m 和 n 代表 l1 和 l2 的长度。
-
空间复杂度:O(max(m,n)),m 和 n 代表 l1 和 l2 的长度。而其实新的 List 最大长度是 O(max(m,n))+ 1,因为我们的 head 没有存储值。
参考文献
- https://zhuanlan.zhihu.com/p/41948568