题干描述:
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
目录
前言:
当时第一眼看见这道题时,觉得这种存储方式类似于栈,于是第一个想法是用栈来解决,先将每个元素移动到栈内,然后分别取出,用一个 longlong 类型的数据存储,最后发现还是会溢出(我还是太天真了~),于是就乖乖模拟了。我目前只想到模拟这一种方法。
方法1:模拟法
方法1分析:
此题是要求你用链表来实现一个“大数加法”,我们只需根据题意,一步步模拟即可。
特别要注意点的是进位时的处理,在中间的进位和末尾的进位都有讲究。
我是用 flag 为 true 或 false 来标记上一次运算是否进位了。
代码如下:
/**
* 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* Head=new ListNode; //设置一个哨兵
ListNode* tail=new ListNode; //设置尾指针
tail=Head;
bool flag=false; //用来标记是否需要进位
while(l1||l2) //这里其实也可以用&&,但是在循环结束后的处理中会有一些代码冗余,因此我在后续优化代码时选择了改为||
{
int l1v=l1?l1->val:0; //如果为指针为空就默认为0,只算另一个链表剩下的节点的值
int l2v=l2?l2->val:0;
int sum=l1v+l2v;
if(flag)
{
sum++;
flag=false;
}
ListNode* node=new ListNode; //创建新节点
if(sum>=10)
{
node->val=sum-10;
flag=true;
}
else
{
node->val=sum;
}
tail->next=node; //连接节点
tail=node; //令tail指向尾节点
if(l1) //如果不为空,就继续到下一位,如果为空,就保持空,便于下一趟循环的继续。
{
l1=l1->next;
}
if(l2)
{
l2=l2->next;
}
}
if(flag) //这里是经常容易忽视的点!最后如果flag为true说明还有一个进位没有处理,因此需要最后特殊处理一下。
{
ListNode* node=new ListNode(1);
tail->next=node;
}
return Head->next; //返回哨兵指向的头节点
}
};
复杂度分析:
时间复杂度:O(),其中 m 和 n 分别为两个链表的长度。我们要遍历两个链表的全部位置,而处理每个位置需要 O(1)的时间。
空间复杂度:O(),返回值不计入空间复杂度。
该题的分享就到这里,本人才疏学浅,肯定会有错误或考虑不周到的地方,如有纠错或建议,非常欢迎在评论区留言,我看见后会立刻回复并在思考后对文章作出合适的修改,感谢阅读~