力扣(LeetCode)两数相加 中等难度 题解(C语言)

力扣(LeetCode)两数相加 中等难度 题解(C语言)

目录

题目内容

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

力扣(LeetCode)两数相加 中等难度 题解(C语言)_第1张图片

解题思路

首先是需要明确本题所提供的链表是不带头结点的单链表,所以采用带头结点的算法会导致出错。
在本题当中,因为数是按照逆序的方式存储的,即链表中的第一个元素实际上是这个数的各位,链表中的最后一个元素是这个链表的最高位。
我们平常在做两个数的加法运算的时候,都是先计算个位,然后将逐步在计算高位。所以这种运算顺序实际上是和本题链表中元素存取的顺序是一致的,即在两个链表中取出第一个元素相加(等价于个位相加),然后初步链表指针逐步向后移动(相当于逐步计算高位)。当然这个过程中一定要注意进位问题。
关于进位问题的理解,两个数相加,例如: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;

}

你可能感兴趣的:(链表,指针,leetcode,数据结构)