题目:
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 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]
官方题目地址:力扣第二题
解释:
在刚开始接题目时,比较懵!!!不懂题目中说的逆序方式存储是啥意思???废话少说,开始解释:逆序方式存储----指的是链表中存储的数字的顺序与我们通常看到的数字的书写顺序是相反的。通常,我们从左到右书写数字,例如数字123,最左边的是最高位(百位),然后是十位,最后是个位。但是在这个特殊的表示法中,链表的第一个节点将代表个位数,第二个节点代表十位数,以此类推,最左边的节点(链表的头节点)代表最低位,而最右边的节点(链表的尾节点)代表最高位。
例如,如果我们有两个数字123和456,按照正常的顺序,我们会将它们写成:
1 2 3
4 5 6
但是按照逆序存储,这两个数字将被存储为:
3 2 1 <-- 链表1
6 5 4 <-- 链表2
在这种表示法中,每个节点只存储一个数字(0-9),并且每个链表的第一个节点(最近个位)实际上是整个数字的最低有效位,而最后一个节点(最远离个位)是最高位。
当你需要将这两个逆序存储的链表相加时,你需要从两个链表的头节点开始,即从最低位开始相加,同时考虑进位。由于每个节点只存储一位数字,相加的结果可能需要进位到下一个更高的位。这个过程一直持续到遍历完两个链表中的所有节点。
解题
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
struct ListNode* head = NULL;//定义头部为 空
struct ListNode* tail = NULL;//定义尾部为 空
int carry = 0;//定义进位
while(l1 || l2)//判断传入的两个结构体指针是否为空 “或运算符”
{
//n1和n2为当前指针所在地址的值
int n1 = l1 ? l1->val : 0;//这里使用了三元运算符? :,如果l1或l2不为NULL,则取它们的val值,否则取0。
int n2 = l2 ? l2->val : 0;
int sum = n1 + n2 + carry;//数值相加
if(!head){//说明新链表还没有创建
head = tail = malloc(sizeof(struct ListNode));//首先保留头部地址,之后开辟对应的结构体大小
tail->val = sum % 10;//取余数,取值
tail->next = NULL;//让tail的下一个指针指向空,防止其成为野指针
}else{//新链表已经创建
tail->next = malloc(sizeof(struct ListNode));//给tail的下一个链节点开辟空间大小
tail->next->val = sum % 10;//让tail节点的下一个链节点的取值
tail = tail->next;//移动尾巴节点
tail->next = NULL;//定义当前尾巴节点的下一个节点为 空
}
carry = sum / 10;//计算当前位置是否产生进位
//循环 l1 和 l2,使其偏移至下一个节点
if(l1){
l1 = l1->next;//移动当前节点
}
if(l2){
l2 = l2->next;//移动当前节点
}
}
//检测产生新的进位--示例3
if(carry > 0){
tail->next = malloc(sizeof(struct ListNode));//开辟空间
tail->next->val = carry;//指向下一个节点数值
tail->next->next = NULL;
}
return head;
}
这个是官方代码:力扣第二题官方代码
在开始看到代码的时候,难免困难,那么我将使用图解方式一一讲诉:
head指针位置一直不变,但是head后面地址上的内容已经更改!!!