题目描述
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
图片和题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers
解题思路
两个数字,通过链表存储每个数字,以倒序的方式存储,这样做的好处是,倒序直接相加即可,只需要考虑进位就行。如果说链表存储的是两个正序的数字,而且是单链表,反而会更难处理。首先可以想到的思路是,每个数字相加,求和之后,需要考虑前面是否有进位。而且,还要考虑当前相加是否会给后面带来进位。代码写的不是很好,因为链表的知识都快忘得差不多了。有些地方可能会有冗余操作,浪费时间。虽然结果正确,但是,通过leetcode调试之后,才改成这版代码。正确步骤应该是你的思路就是正确,然后在写代码,不能有逻辑问题。while循环结束的条件,是l1和l2不为空,而不是l1->next和l2->next不为空,不能漏掉尾节点的数值。当l1和l2有一个为空,就应该停止,继续对剩下一个不为空的继续求和。
我一般在做链表题的时候都会画出链表的图,这样方便理解和写代码。但是有人可能不需要。
代码实现
1.这是第一版代码,写的不是很好,内存占用率很好,而且速度也不是很快。优化的地方肯定有很多,冗余也有很多。“小白的痛苦”
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
//头结点需要单独处理,因为头结点和其他节点的操作不同,逆置链表原来的头结点相当于尾节点,next为null
//头结点是链表指向的真实节点,但数据值是空的,这样做的好处是while循环中没有额外的操作。
//l3首先指向头结点,记录当前的尾节点。尾插法
ListNode* l3 = new ListNode(-1, NULL);
ListNode *tail = l3;
//数字相加,需要考虑进位
int carry = 0;
while(l1 != NULL && l2 != NULL) {
//printf("1");
int itemp = l1->val + l2->val + carry;
//printf("%d ", itemp);
if(itemp >= 10) {
carry = 1;
itemp -= 10;
} else {
carry = 0;
}
ListNode *temp = new ListNode(itemp, NULL);
tail->next = temp;
tail = tail->next;
l1 = l1->next;
l2 = l2->next;
}
// carry是来自之前的进位
while(l1 != NULL) {
int itemp = l1->val + carry;
if(itemp >= 10) {
carry = 1;
itemp -= 10;
} else {
carry = 0;
}
ListNode *temp = new ListNode(itemp, NULL);
tail->next = temp;
tail = tail->next;
l1 = l1->next;
}
while(l2 != NULL) {
int itemp = l2->val + carry;
if(itemp >= 10) {
carry = 1;
itemp -= 10;
} else {
carry = 0;
}
ListNode *temp = new ListNode(itemp, NULL);
tail->next = temp;
tail = tail->next;
l2 = l2->next;
}
// l1和l2都已经为null,但是最后一个尾节点还有进位,则需要在新建一个节点。
if(carry == 1) {
ListNode *temp = new ListNode(1, NULL);
tail->next = temp;
}
//当前l3指向头结点,找到第一个节点,抛弃头结点。
return l3->next;
}
2.第一版本的优化,其实都是leetcode官方题解,我只是复制过来了可参考上面的来源链接找到详细内容。
步骤1.判断l1和l2是否null,不为空取出数值相加,否则数值为0
步骤2.相加的时候考虑上一个是否有进位,是否对下次产生进位。
步骤3.建立节点,尾节点向后移动一个
步骤4.判断l1和l2是否为空,不为空向后移动一个。
步骤5.是否有进位,有进位需要建立值为1的元素。
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* l3 = new ListNode(-1, NULL);
ListNode *tail = l3;
int carry = 0;
while(l1 || l2) {
int n1 = l1 ? l1->val : 0;
int n2 = l2 ? l2->val : 0;
int n3 = n1 + n2 + carry;
carry = n3 / 10; //先求出下一次是否进位,进位是为下次准备的
n3 = n3 % 10; //模余
tail->next = new ListNode(n3);
tail = tail -> next;
if(l1) {
l1 = l1->next;
}
if(l2) {
l2 = l2->next;
}
}
if(carry == 1) {
tail->next = new ListNode(1);
}
return l3->next;
}