问题描述
给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例1:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:
输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]
解题思路
这道题我自己的想法是,直接遍历两条链表,两个while循环,第一个while直接做加法,挨个做加法,因为题目给出的是条件是两个链表存储的数据是逆序,那我就直接遍历两个链表,首先根据进位标识符进行判断是否需要进位,然后根据是否需要进位从而逐个对链表的节点进行相加,如果相加后的结果需要进位,进位标识符置为1,否则为-1。第一个while循环跳出之后,第二个while循环则是链接剩下的节点与结果链表,也就是如果某个加数的长度比较长,那么高位的数据肯定需要直接链接的,所以第二个while循环就做链接操作。但此时需要注意两点:1.仍要考虑进位,因为有可能在之前的相加 操作中仍存在进位的情况,比如999+1的这种情况,所以第二个while循环仍要做进位判断;2.仍是上述情况,在最后的最高位处,999+1得到的结果是1000,结果数是要比原来两个链表都要长,所以,我们在最后需要再做一次进位标识符判断,如果此时仍有进位,那么我们就要新链接一个数据为1的节点到结果链表中。最终代码如下:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
//数字逆序存储,那考虑尾插法存储链表,因为数字从个位开始拿,刚好逆序
/*
输入数据的头一个数字不能是0,也就是输入要合法,不存在高位为0的情况
示例应该是没有头节点的但链表
单链表肯定涉及遍历,时间复杂度为n,选择最短的链表进行遍历,直接进行相加,存储到结果链表中,
中间使用一个进位标志符进行判断是否需要进位
*/
ListNode *p,*q,*r,*tmp;//p,q遍历指针
int flag = -1;//进位标志
p = l1;
q = l2;
// res = (ListNode *)malloc(sizeof(ListNode));
ListNode *res = new ListNode();
r = res;
while (p!=NULL && q!=NULL)//当两个链表都没有到最末尾的时候
{
// tmp = (ListNode *)malloc(sizeof(ListNode));//存放结果
ListNode *tmp = new ListNode();
if(flag==1)
{
if(p->val+q->val+1 == 10)
{
tmp->val=0;
r->next = tmp;
r=r->next;
flag=1;
}
else if(p->val+q->val+1>10)
{
tmp->val=p->val+q->val+1-10;
r->next = tmp;
r=r->next;
flag=1;
}
else if(p->val+q->val+1<10)
{
tmp->val=p->val+q->val+1;
r->next = tmp;
r=r->next;
flag=-1;//进位重置
}
}
else//不需要进位的时候
{
if(p->val+q->val == 10)
{
tmp->val=0;
r->next = tmp;
r=r->next;
flag=1;
}
else if(p->val+q->val>10)
{
tmp->val=p->val+q->val-10;
r->next = tmp;
r=r->next;
flag=1;
}
else if(p->val+q->val<10)
{
tmp->val=p->val+q->val;
r->next = tmp;
r=r->next;
flag=-1;//进位重置
}
}
q=q->next;
p=p->next;
}
while (q!=NULL||p!=NULL)//任意一个链表还没有遍历完成
{
// tmp = (ListNode *)malloc(sizeof(ListNode));//存放结果
ListNode *tmp = new ListNode();
if(q!=NULL)
{
if(flag==1)//此时有进位的话
{
if(q->val+1==10)
{
tmp->val = 0;
r->next = tmp;
r=r->next;
flag=1;
}
else{
tmp->val = q->val+1;
r->next = tmp;
r=r->next;
flag=-1;
}
}
else
{
tmp->val = q->val;
r->next = tmp;
r=r->next;
}
q=q->next;
}
else if(p!=NULL)
{
if(flag==1)//此时有进位的话
{
if(p->val+1==10)
{
tmp->val = 0;
r->next = tmp;
r=r->next;
flag=1;
}
else{
tmp->val = p->val+1;
r->next = tmp;
r=r->next;
flag=-1;
}
}
else
{
tmp->val = p->val;
r->next = tmp;
r=r->next;
}
p=p->next;
}
}
if(flag==1)//此时还有进位的话,也就是比如999+1这种情况,就要在结果链表中再多一个节点
{
tmp = new ListNode();
tmp->val = 1;
tmp->next = NULL;
r->next = tmp;
r=r->next;
}
return res->next;
}
};
最终的提交效果其实很差,虽然通过了,但时间和空间上的开销不低,所以还可以优化。无意间看到社区有这种解法:
进行两个链表遍历的时候,他只用了一个变量进行遍历,另一个直接用的链表本身进行遍历,这样就减少了空间的开销,后续如果某个链表遍历完,那么直接将这两个链表合并为一个链表,这样的操作就在空间和时间上少了开销。