LeetCode 2、两数相加(C)

本文详细记录了一名编程初学者在LeetCode上练习两数相加问题的过程,通过分析错误代码和正确代码,深入理解链表操作和递归解法。在错误代码部分,作者指出头插法导致的问题,并解释了为何需要采用尾插法。在正确的解决方案中,作者展示了如何使用尾插法构建链表,并给出了执行过程的详细步骤。最后,作者尝试将问题转化为递归形式,虽然遇到一些困难,但展现了对递归解法的探索精神。
摘要由CSDN通过智能技术生成

  作者只是一个小白,最近希望能提升自己的代码水平,所以开始刷leetcode。写博客是为了整理自己的学习内容,难免会出错。如果有大大发现,非常欢迎指正哦!

题目:2、两数相加

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

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

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

实例:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.


题解

  这道题思路并不复杂,就是将l1,l2对应的数字和进位相加,相加的结果的个位数填入对应位置,相加的结果的十位数作为进位存储。最容易忘的一点就是最高位相加后可能也会有进位。

//伪码
//add为进位
while(l1 && l2 && add){
	if(l1){
		add = add + l1->val;
		l1 = l1->next;
	}
	if(l2){
		add = add + l2->val;
		l2 = l2->next;
	}
	result->val = add % 10;//取个位数
	add = add / 10;//取十位数
	使result指向它的下一级;//形成链表
}
return result;

  所以这应该主要看我们对单链表的操作。个人感觉这篇博客写得最全:C语言实现单链表的创建及基本操作


while循环

  这边先贴我第一次写的错误 的代码

struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2)
{
    int add = 0, val = 0;
    struct ListNode *result;
    result = malloc(sizeof(struct ListNode));
    while (l1 || l2 || add)
    {
        if (l1)
        {
            val += l1->val;
            l1 = l1->next;
        }
        if (l2)
        {
            val += l2->val;
            l2 = l2->next;
        }
        val += add;
        result->val = val % 10;
        add = val / 10;
        val = 0;
        result->next = result;//问题主要在这
    }
    result = result->next;
    return result;
}

  这段代码里我主要有两个错误。一个是result->next = result。例如我要计算,12+23,根据题目的意思,我先算得result->val=2+3=5,然后将5存入到result->next->val中。按照我的想法是接下来计算十位数result->val=1+2=3,而这不会改变result->next->val中的值,然后就一层一层叠下去。但实际上首先我的想法是用头插法创建单链表,但题目要求的结果应该是用尾插法,其次最重要的一点是result是一个指针,里面存储的是地址,result->next = result这一句实际上是让result里每一个next都指向同一个地址,然后第二轮执行result->val=val%10的时候,其实导致整个result的每一个next的val值都发生改变。

测试用例: 342+465

第一轮: 刚执行完result->val=val%10

  我们可以看到result->val=7,result->next->val中为空,二者存储的地址不同。
在这里插入图片描述
 

第一轮: 刚执行完result->next=result

  我们会发现result中val值均为7,而且地址也都一样。
在这里插入图片描述
 

第二轮: 刚执行完result->val=val%10

  因为指向的空间是一样的,所以这一次就同时变为4+6=10,取个位数为0。
在这里插入图片描述
 

第二轮: 刚执行完result->next=result

  因为地址已经是一样的,没有变,所以这一句从第二轮开始已经没有效果了。
在这里插入图片描述
  那错误的地方已经知道了,要怎么改呢?先来看看正确的代码是怎么样的。
 
 
这是正确的代码。是我根据分享的那篇博客里单链表的尾插法来改的。
执行用时:12ms
排名:超过 81% 提交记录

struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2)
{
    int add = 0;
    struct ListNode *result;
    struct ListNode *p;//新建一个结点指针
	struct ListNode *r;//再建立一个尾指针
    result = malloc(sizeof(struct ListNode));
    memset(result,0,sizeof(struct ListNode));
	r=result;//很重要的一步,令尾指针r指向头结点l,便于做尾插入
    while (l1 || l2 || add)
    {
        if (l1)
        {
            add += l1->val;
            l1 = l1->next;
        }
        if (l2)
        {
            add += l2->val;
            l2 = l2->next;
        }
        p=malloc(sizeof(struct ListNode)) ;//建立一个新结点
        memset(p,0,sizeof(struct ListNode));
        p->val = add % 10;
        add = add / 10;
        r->next = p;//尾指针的指针域指向新结点p
        r=p;//再让尾指针放在p后面,尾指针永远在最后
    }
    result = result->next;
    return result;
}

 

测试用例: 642+465

第一轮: 执行r = result

  使得二者指向同一个空间。
在这里插入图片描述
 

第一轮: 刚执行完r->next = p

  因为r和result二者指向同一个空间,所以给r->next赋值,同时给result->next赋值,所以我们可以发现r->next->val == result->next->val == p->val == 7。在这里插入图片描述

 

第一轮: 刚执行完r = p

  这一步我一开始没有理解。但我们来看r,p,result中存的内容就比较好理解。result->next指向的空间和r是一致的,这就使得我们第二轮执行r->next = p时,可以实现result->next->next = p,第三轮时,同样是r->next = p,实现的是result->next->next->next = p。
在这里插入图片描述

 

第二轮: 刚执行完r->next = p

  r->next->val = 0,而result->next->next->val的值我忘了展开,但是我们看二者的存储的地址空间是一样的,所以也是0,符合预期。
在这里插入图片描述
 

第二轮: 刚执行完r = p

在这里插入图片描述

 

第三轮: 刚执行完r->next = p

在这里插入图片描述

 

第三轮: 刚执行完r = p

在这里插入图片描述
 

第四轮: 刚执行完r->next = p

在这里插入图片描述

 

第四轮: 刚执行完r = p

  至此结束循环。
在这里插入图片描述


while循环 反思

  代码是成功执行了,但还有一些注意的的地方。

  • 因为我们的代码是直接在l1和l2上直接操作的,代码运行后,l1和l2就被破坏了。这在许多情况里并不合适。所以我们要把l1,l2中的数据先复制一份,在复制上进行操作。
  • 对于指针这些分配好空间后,要记得清0初始化。我代码里是用memset全部清0了,而如果没有memset这一句,那么在 p->val = add % 10; 这一句之后要记得加 p->next = NULL;
  • 代码运行后result中头指针中是空值,所以要result = result->next,之后return result。
  • 再附一份代码
    执行用时:0ms
    排名:超过 100% 提交记录
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    struct ListNode *lst1 = l1;
    struct ListNode *lst2 = l2;
    struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *temp = head;
    int t = 0;
    while (lst1 || lst2 || t) {
        if (lst1) {
            t += lst1->val;
            lst1 = lst1->next;
        }
        if (lst2) {
            t += lst2->val;
            lst2 = lst2->next;
        }
        struct ListNode *NewNode = (struct ListNode*)malloc(sizeof(struct ListNode));
        NewNode->val = t % 10;
        NewNode->next = NULL;
        temp->next = NewNode;
        temp = temp->next;
        t /= 10;
    }
    return head->next;
}

递归

  写完代码后想再改成递归的形式。但是leetcode报错,而vscode中跑是可以跑,但是有警告。问题应该是说我的代码并不是任何一个分支都有返回的内容。

solution.c: In function ‘result’
Line 23: Char 1: error: control reaches end of non-void function [-Werror=return-type] [solution.c]
}
^
cc1: some warnings being treated as errors

  以下是我的代码。代码中的return 0,如果注释掉就会报错,如果不注释掉就会返回空值。但我的理解是除非满足(!l1 && !l2 && !add)这个条件,否则不应该是永远递归吗?为什么会跑到return 0;这一步。
  如果有大大知道该怎么改,烦请评论区告诉我吧!多谢啦!

struct ListNode *result(struct ListNode *l1, struct ListNode *l2, struct ListNode *ret,struct ListNode *r,int add){
    if(!l1 && !l2 && !add){
        ret=ret->next;
        return ret;
    }
    if (l1)
    {
        add += l1->val;
        l1 = l1->next;
    }
    if (l2)
    {
        add += l2->val;
        l2 = l2->next;
    }
    struct ListNode *p=(struct ListNode*)malloc(sizeof(struct ListNode)) ;//建立一个新结点
    memset(p,0,sizeof(struct ListNode));
    p->val = add % 10;
    r->next = p;
    r=p;
    result(l1,l2,ret,r,add/10);
    // return 0;
}

struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2)
{
    struct ListNode *ret=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *r=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *r1=l1;
    struct ListNode *r2=l2;
    r=ret;
    return result(r1,r2,ret,r,0);
}
  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值