P2 两数相加
题目链接:2. 两数相加.
题目描述
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
题解
思路
由题目描述可知,两个整数是按照逆序的方式存储在两个链表中的,以低位开始,那就可以从链表头开始同步遍历这两个链表,每移动一步,将两结点上的两个数(x,y)相加起来,由于是两个个位数之和(sum),所以sum的范围为:[0,18],当sum≥10时,产生进位carry,所以我们在计算sum时,sum=x+y+carry。
若这两个链表的长度不一样,那么在短链表遍历完时,在之后的结点相加中,短链表的结点值均为0
当两个链表均遍历完成时,还需要检验一次carry,若carry=1,则还需要在结果链表尾再添加一个值为1的结点。
算法
伪代码:
- ①创建结果链表,头指针为first,并先添加一个无用结点
- ②进位标志carry初始化为0
- ③p1,p2分别初始化为两个链表的头指针
- ④使用p1,p2遍历这两个链表,直到两个链表均遍历完
- x设置为p1所指结点上的值,若p1为nullptr,x设置为0
- y设置为p2所指结点上的值,若p2为nullptr,y设置为0
- sum=x+y+carry
- carry=sum/10
- 将(sum%10)添加到结果链表尾端
- 若p1不为nullptr,则p1指向下一个结点
- 若p2不为nullptr,则p2指向下一个结点
- ⑤若carry==1,在结果链表尾再添加一个值为1的结点
- ⑥丢弃结果链表中的第一个无用结点,返回first->next
struct ListNode {
int val;
ListNode* next;
ListNode(int x): val(x),next(NULL) {}
};
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1,ListNode* l2) {
ListNode* first=new ListNode(-1); //存放结果的链表,头指针为first,第一个结点为无用结点
ListNode* cur=first;
ListNode* p1=l1;
ListNode* p2=l2;
int sum;
int carry=0; //进位标志
while(p1||p2){
int x=p1?p1->val:0;
int y=p2?p2->val:0;
sum=x+y+carry;
carry=sum/10;
cur->next=new ListNode(sum%10);
cur=cur->next;
if(p1){
p1=p1->next;
}
if(p2){
p2=p2->next;
}
}
if(carry){
cur->next=new ListNode(1);
}
return first->next;
}
};
复杂度分析
假设 m m m 和 n n n 分别表示 l 1 l1 l1 和 l 2 l2 l2 的长度
- 时间复杂度: O ( m a x ( m , n ) ) O(max(m, n)) O(max(m,n)),上面的算法最多重复 m a x ( m , n ) max(m, n) max(m,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 。