两数相加
LeetCode热题Hot100题
002两数相加(中等)
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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]
方法一
解题思路:
创建一个初始值为0的空链表用于接收计算结果,初始化链表的地址为自动匹配类型,初始化count用于记录进位。
使用while循环l1或l2不全为空的条件为真,定义sum用于接收计算l1+l2+count(进位)的结果。
将sum对10取余的结果存入接收计算结果的链表gentle中,并移动链表到下一位,计算count/10,当count小于10,count计算结果为0,大于10,计算结果为1;判断l1和l2是否为空,移动l1和l2,直到while计算结束。
若最后还有进位,补1。
补充知识:
auto的原理就是根据后面的值,来自己推测前面的类型是什么。
auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
//初始化链表为空,用于存放结果
ListNode *gentle = new ListNode(0);
//自动匹配指针类型
auto p = gentle;
//记录进位
int count = 0;
while (l1 || l2)
{
//sum用于接收加法的计算结果
int sum = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + count;
//将sum对10取余的结果存放进链表dummy中
p->next = new ListNode(sum % 10);
//count接收除以10的值,大于10,count进位为1,否则为0
count = sum / 10;
//存放结果的链表移动到下一个节点
p = p->next;
//l1,l2链表后移
if (l1)
l1 = l1->next;
if (l2)
l2 = l2->next;
}
if (count)
p->next = new ListNode(1);
return dummy->next;
}
};
方法二
算法思路:
将长度较短的链表在末尾补零使得两个连表长度相等,再一个一个元素对其相加(考虑进位)
获取两个链表所对应的长度
在较短的链表末尾补零
对齐相加考虑进位(定义进位count,每次循环对count进行/10运算)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int len1=1;//记录l1的长度
int len2=1;//记录l2的长度
ListNode* p=l1;
ListNode* q=l2;
while(p->next != NULL)//获取l1的长度
{
len1++;
p=p->next;
}
while(q->next != NULL)//获取l2的长度
{
len2++;
q=q->next;
}
if(len1>len2)//l1较长,在l2末尾补零
{
for(int i=1;i<=len1-len2;i++)
{
q->next=new ListNode(0);
q=q->next;
}
}
else//l2较长,在l1末尾补零
{
for(int i=1;i<=len2-len1;i++)
{
p->next=new ListNode(0);
p=p->next;
}
}
p=l1;
q=l2;
int count=0;//记录进位
ListNode* l3=new ListNode(-1);//存放结果的链表
ListNode* w=l3;//l3的移动指针
int i=0;//记录相加结果
while(p!=NULL&&q!=NULL)
{
i=count+p->val+q->val;
w->next=new ListNode(i%10);
count=i / 10;
w=w->next;
p=p->next;
q=q->next;
}
if(count)//若最后还有进位
{
w->next=new ListNode(1);
w=w->next;
}
return l3->next;
}
};
方法三
因为输入的两个链表都是逆序存储数字的位数的,因此两个链表中同一位置的数字可以直接相加。不是直接相加而是定义一个中间变量carry存储两位相加的值,但是在用中间变量累加前需要判断此链表不为空(就是为了避免长度不一样),为空的时候就不进行累加即:
/* 只要不为空就继续求和 */
if(l1 != NULL) carry += l1->val;
if(l2 != NULL) carry += l2->val;
然后将以carry%10的值定义一个新的结点将其插入到虚拟头节点的后面这样就可以得到两节点求和后在新链表重的值,然后计算carry/10有进位值的话就直接累加到下次的计算当中。
注意:此外,如果链表遍历结束后,有 carry>0,还需要在答案链表的后面附加一个节点,节点的值为 carry。所以判断有没有遍历完是while(l1 || l2 || carry)而不是while(l1 || l2)
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
/* 定义一个新的链表用于存储求和的结果 */
ListNode* dummyHead = new ListNode(0);
auto p = dummyHead;
/* 定义一个变量用于保存进位 */
int count = 0;
/* 因为不知道l1和l2的长短所以只要有一个没有遍历完就继续遍历 遍历完的就不执行
*
* 第一次写while(l1 || l2)会错因为漏掉了最后一个进位《== 特别哟注意
* /
while(l1 || l2 || count){
/* 只要不为空就继续求和 */
if(l1 != NULL) count += l1->val;
if(l2 != NULL) count += l2->val;
/* 创建一个节点插入到新的链表并且值初始化为l1->val+l2->val的个位数 */
ListNode* tmp = new ListNode(count%10);
/* 插入结点tmp因为是从头开始插入所以只需要每次更新cur */
p->next = tmp;
p = p->next;
/* 只要链表不为空就继续遍历下一个节点 */
if(l1 != NULL) l1 = l1->next;
if(l2 != NULL) l2 = l2->next;
/* 获取上个节点的进位值 加到下个节点的运算中 */
count /= 10;
}
/* 注意这里不返回dummyHead因为这里相当于一个虚拟头节点 下一个才是正真的头节点 */
return dummyHead->next;
}
};
l2 = l2->next;
/* 获取上个节点的进位值 加到下个节点的运算中 /
count /= 10;
}
/ 注意这里不返回dummyHead因为这里相当于一个虚拟头节点 下一个才是正真的头节点 */
return dummyHead->next;
}
};