力扣LeetCode第二题

一、题目描述

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

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

你可以假设除了数字 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]
 

提示:

每个链表中的节点数在范围 [1, 100] 内
0 <= Node.val <= 9
题目数据保证列表表示的数字不含前导零。

二、解答

2.1 一种容易想出,但代码冗余复杂的过渡解答

// /**
//  * Definition for singly-linked list.
//  * struct ListNode {
//  *     int val;
//  *     struct ListNode *next;
//  * };
//  */

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    /**

    */
    struct ListNode *p = (struct ListNode*)malloc(sizeof(struct ListNode));
    //初始化p是因为可能链表只有一位 不初始化就会runtimeerror
    p -> val = 0;
    p -> next = NULL; 
    struct ListNode *a = p; //用a来记录p的表头

    int flag = 0; //进位
    int t=0;//临时变量 作为每一轮的加和

    while(l1 && l2){
        //t等于l1 + l2 + flag 就像算术那样,把这一位上两个数和进位加起来。
        t = l1 -> val + l2 -> val + flag;
        if(t > 9){ //如果大于等于10了,那么需要进位 flag就标记为1
            t = t%10;
            flag = 1;
        }else{ //这里要专门写一下flag = 0,因为可能会有上一轮进位的1,就加在这一轮中 ,并且这一轮没有进位。
            flag = 0;
        }

        //赋值再走到下一个结点
        p -> val = t;

        printf("l1:%d,l2:%d,t:%d,p:%d,flag:%d\n",l1 -> val,l2 -> val,t,p->val,flag);

        //l1 l2都走向下一节点
        l1 = l1 -> next;
        l2 = l2 -> next;

        //如果l1 l2 均为空 而且flag = 0,说明已经全部完成。
        //因为是提前为下一节点分配内存并初始化 
        //若不加该判断,如果l1 l2相同长度且最后一位不需要进位的时候会多出一位为0的情况
        if( l1 == NULL && l2 == NULL && flag == 0) break;

        //为下一节点分配空间和初始化 走到下一节点
        p -> next= (struct ListNode*)malloc(sizeof(struct ListNode));
        p  = p ->next;
        p -> val = NULL;
        p -> next = NULL;



    }

    while(l1) {
        //这个函数是因为l2已经空了 l1还没空 所以需要继续将l1的内容复制到p

        //t的部分同上
        t = l1 -> val + flag;
        if(t > 9){
            t = t%10;
            flag = 1;
        }else{
            flag = 0;
        }

        //同上
        p -> val = t;

        //原理同上 l1的后面已经空了 而且没有进位 则不需要分配p的下一个空间 否则会多一位
        //这里是判断的l1的next是否为空 所以 l1 = l1 ->next在判断后
        // 上面的函数是判断l1是否为空 所以 =next在判断前
        if(l1 -> next == NULL && flag == 0) break;
        p -> next= (struct ListNode*)malloc(sizeof(struct ListNode));;
        p  = p ->next;
        p -> val = 0;
        p -> next = NULL;

        l1 = l1 ->next; 
    }

    while(l2){
        //这个函数是因为l1已经空了 l2还没空 所以需要继续将l2的内容复制到p
        //内容与原理同l1 仅仅是改为l2
        t = l2 -> val + flag;
        if(t > 9){
            t = t%10;
            flag = 1;
        }else{
            flag = 0;
        }


        p -> val = t;
        if(l2 -> next == NULL && flag == 0) break;
        p -> next= (struct ListNode*)malloc(sizeof(struct ListNode));;
        p  = p ->next;
        p -> val = 0;
        p -> next = NULL;

        l2 = l2 ->next;

    }

    //如果l1 l2都加完了 但是最后还有进位 不要忘了加上。
    if(flag) p -> val = flag;

    return a; //返回的是p的头节点
}

1568 / 1568 个通过测试用例

状态:通过

执行用时: 16 ms

内存消耗: 7.4 MB


2.2 改进后代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


//改进后
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    //如果不初始化 那么head指向它的时候就会指向随即地址 成为野指针
    struct ListNode *tail = (struct ListNode*)malloc(sizeof(struct ListNode)); 
    struct ListNode *head = tail;

    int carry = 0; //进位

    while(l1 || l2 || carry){ //不要忘了进位carry 否则最后一位和恰好为10会少一位
        int sum = carry; //如果上一轮的carry有值会先赋值过来

        if(l1){ //l1还没空 如果空了就不会进入这里 相当于sum+了个0
            sum += l1 -> val;
            l1 = l1 -> next;
        }
        if(l2){ //同理l1
            sum += l2 -> val;
            l2 = l2->next;
        }

        carry = sum /10 ;
        sum = sum % 10;

        tail -> next = (struct ListNode*)malloc(sizeof(struct ListNode)); //带头结点
        tail = tail -> next;
        tail -> val = sum;
        tail -> next = NULL;
    }

    return head->next;
}

1568 / 1568 个通过测试用例

状态:通过

执行用时: 12 ms

内存消耗: 7.5 MB


期待后续改进~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值