力扣(LeetCode)两数相加 中等难度 题解(C语言)
目录
题目内容
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
解题思路
首先是需要明确本题所提供的链表是不带头结点的单链表,所以采用带头结点的算法会导致出错。
在本题当中,因为数是按照逆序的方式存储的,即链表中的第一个元素实际上是这个数的各位,链表中的最后一个元素是这个链表的最高位。
我们平常在做两个数的加法运算的时候,都是先计算个位,然后将逐步在计算高位。所以这种运算顺序实际上是和本题链表中元素存取的顺序是一致的,即在两个链表中取出第一个元素相加(等价于个位相加),然后初步链表指针逐步向后移动(相当于逐步计算高位)。当然这个过程中一定要注意进位问题。
关于进位问题的理解,两个数相加,例如:16+15 = 31。在做个位运算的时候(6+5),我们在结果的个位上存储的是1(11%10),进位是1(11/10);十位运算的时候(1+1+1),其中前两个1分别为16和15的十位,第三个1是进位。
根据上面的例子,我们可以知道新的链表每一个结点保存的数值(p、q为两个待相加的链表):(p->val+q->val+carry)%10,进位carry=(p->val+q->val+carry)/10。
代码
`.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
int length(struct ListNode* l){//求不带头结点的单链表长度
struct ListNode * p = l;
int i = 0;
while(p != NULL){
p = p->next;
i++;
}
return i;
}
//此题是不带头结点的单链表
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
struct ListNode* s, *p , *q,*p1 = l1,*p2 = l2;
int len1 = length(l1);//获取链表l1长度
int len2 = length(l2);//获取链表l2长度
//在较短一个后面进行补零,使得两个链表的长度保持一致
while(p2->next!=NULL){
printf("%d",p2->val);
p2=p2->next;//将指向l2的q2指针指向链表的最后一个节点,便于在l2后面加0
}
while(p1->next!=NULL){
printf("%d",p1->val);
p1=p1->next;//将指向l1的q1指针指向链表的最后一个节点,便于在l1后面加0
}
if(len1>len2){
int dist = len1-len2;
while(dist--){
//链表1的长度大于链表2的长度,在链表2的后面进行尾插
s = (struct ListNode*)malloc(sizeof(struct ListNode));
s->val = 0;
p2->next = s;
p2 = s;
}
p2->next = NULL;
}
else if(len1<len2){
int dist = len2-len1;
//链表1的长度小于链表2的长度,在链表1的后面进行尾插
while(dist--){
s = (struct ListNode*)malloc(sizeof(struct ListNode));
s->val = 0;
p1->next = s;
p1 = s;
}
p1->next = NULL;
}
//以上是在两个链表长度不均等的情况下,使得两个链表长度相等的操作
//如果做了以上操作,就相当于将新的l1,l2赋予给p、q,如果原本就长度相等,可以看成是将原本的l1,l2赋予给p、q
q = l2;
p = l1;
struct ListNode* l3 = (struct ListNode*)malloc(sizeof(struct ListNode));//将运算的结果存入l3
struct ListNode* r = l3;//便于后面进行头插操作,先将l3赋予给r
//此题不带头结点,所以l3也是不带头结点的链表,所以应该先算出第一个值赋予给r,这样便于后面计算
int temp_next = 0,sum = 0,i = 0;//temp_next表示的是上一步运算的进位,sum表示的是两值和进位相加的和
sum = p->val+q->val;
//例如:假设p->val = 5,q->val = 6;则两数相加的进位为(5+6+0)/10,存入l3的值为(5+6+0)%10,其中0为进位,因为此处是第一个结点,没有上一位来的进位,所以进位为0
r->val = (sum%10);//存入l3的值
temp_next = sum/10;//运算后的进位
//计算完两个链表的第一个结点之后,指向各自的下一个结点
p = l1->next;
q = l2->next;
while(p!=NULL && q!=NULL){
sum = p->val+q->val+temp_next;//求和
int val_store = sum%10;//存入l3的值
temp_next = sum/10;//进位
//进行尾插法:进行尾插法的原因是:题目要求还要将结果逆序存储
s = (struct ListNode*)malloc(sizeof(struct ListNode));
s->val = val_store;
r->next = s;
r = s;
p = p->next;
q = q->next;
}
if(temp_next!=0){
//如果进位不为0,则应该将进位插入L3
s = (struct ListNode*)malloc(sizeof(struct ListNode));
s->val = temp_next;
r->next = s;
r = s;
}
//进行尾插法,最后要将其指向空
r->next = NULL;
return l3;
}