复习leetcode第二题:两数相加

news2025/1/20 10:53:01

本文会给出笔者自己的解答(代码较为冗余,其实就是屎山代码)以及优秀代码的解析

下图是题目

b98ab95f90244322a1a09ac50efca748.png

解法1(笔者所使用的办法): 

解题思路:

以下思路是基于示例1(上图)思考的

步骤1:因为该函数只传来了两个链表的首元结点指针,所以我们不难想到可以创建一个新链表来存放两链表相加的内容

步骤2:由于我们最后需要返回新链表的首元结点指针,而新链表不断创建以后,用于创建链表的指针也后移了,因此我们还需要创建一个指针phead,用作最后的函数返回

步骤3:题目给我们的结构体名称为Listnode(在注释行写了),笔者觉得大小写切换太麻烦了,因此这边改成了listnode

步骤4:通过示例1我们也不难发现,我们需要使用循环语句来多次让两个链表的结点内容相加,并存放到新链表中;而循环的退出条件应该是l1链表和l2链表的所有结点的数据全部相加完了,即l1、l2同时为空指针

上述步骤代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode listnode;
listnode* buynode(int x) //用于创建新链表的函数
 {
    listnode* newnode = (listnode*)malloc(sizeof(listnode));
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
}
                                    //l1首元结点指针      //l2首元结点指针
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) 
{
    int count=0;
    listnode* newnode=buynode(0); //创建一个新链表的首元结点,之后每次创建新链表都传0值,因为只有给新链表结点0这个初值才不会影响结果
                                  //当然也并不是必须给新链表的结点赋初值,这里只是为了保险起见
    listnode* phead=newnode;
    while(l1||l2) //退出条件为两个指针全为空指针
    {

    ……;
    
    }
    return phead;
}

1f08a6952a6c4ca58a8f0183ef310a4c.png

示例1的情况:

示例1中出现了两数相加等于10的情况,最后l1、l2结点所对应的新链表结点留下来的数据为0,然后把 1这个数值 进1位和后续结点数据内容相加,这也就导致了 4+3+1 = 8。但我们不难发现,l1、l2的结点数据相加最大值为18(即使加上1也只有19),因此只有可能把1这个数值进1位,不可能把1以外的数值进1位。 

因此我们可以进行一个分支语句,分为了最后l1、l2结点数据相加 大于等于10 小于等于9两种情况;然后通过一个计数器count,来判断是否需要对后一个结点数据加1

每次相加完,让l1、l2、新链表都往后移动一位

代码如下所示:

 

        //分为l1+l2 <=9 以及 l1+l2 >=10 两种情况
        //<=9
                if((l1->val)+(l2->val)+count<=9) 
        {
            newnode->val=(l1->val)+(l2->val)+count;
            count=0;
        }
        //>=10
        else
        {
            newnode->val=(l1->val)+(l2->val)+count-10;
            count=1;
        }
            l1=l1->next;
            l2=l2->next; 
            newnode->next=buynode(0);
            newnode=newnode->next;

bcd5c9e8d2374ad2af6f20353d02538e.png

示例2的情况用示例1的代码就能解决,此处不再讲解。

f6607e7e89c5422dbc8b24a36c825832.png

示例3的情况:

该示例告诉我们,l1为空时,l2不一定为空;l2为空时,l1不一定为空。

因此,会有三种情况:分别是l1、l2都不为空,只有l1为空,只有l2为空。此处可以通过三条分支语句来解决。

当l1为空,l2不为空时,把l1继续往后移动一位代码会出错(对空指针进行解引用操作),因此我们需要在不同的分支语句里面对不同情况进行不同的向后移位操作

而当把所有数据相加完,l1、l2都为空的时候,有可能count仍为1(示例3输出里最后会出现一个1的原因),因此我们需要在整个循环语句后,解决这个问题。直接在新链表最后面加上一个结点,且最后一个结点数据域只可能为1(上文已经讲解过只可能为1的原因)

代码如下所示:

 

        if(l1&&l2) //两指针都非空
        {
        //分为l1+l2 <=9 以及 l1+l2 >=10 两种情况
        //<=9
                if((l1->val)+(l2->val)+count<=9) 
        {
            newnode->val=(l1->val)+(l2->val)+count;
            count=0;
        }
        //>=10
        else
        {
            newnode->val=(l1->val)+(l2->val)+count-10;
            count=1;
        }
            l1=l1->next;
            l2=l2->next; 
        }
        else if(l1) //l1还不为空的情况
        {
            if((l1->val)+count<=9)
            {
                newnode->val=(l1->val)+count;
                count=0;
            }
            else
            {
            newnode->val=(l1->val)+count-10;
            count=1;
            }
             l1=l1->next; //为防止对空指针l2进行解引用操作
            }    
            else if(l2) //l2还不为空的情况
            {
            if((l2->val)+count<=9)
            {
                newnode->val=(l2->val)+count;
                count=0;
            }
            else
            {
            newnode->val=(l2->val)+count-10;
            count=1;
            }
             l2=l2->next; //为防止对空指针l1进行解引用操作
            }  
        if(count==1) //两个指针全都为空但count还是为1,是对示例3的解决
        {
        newnode->next=buynode(1); //直接在newnode指针最后面加上一个结点,且最后一个结点数据域只可能为1
        }  

由于新链表一直要创建到l1、l2都为空,那么在循环语句(循环语句退出条件为l1、l2都为空)里的新链表创建就不需要加以限制了呢?

答:如果不加以限制,会出现下图的情况,这是由于在最后一次l1、l2结点数据相加并放入新链表以后,还会再进行一次新链表的结点创建

解决方法:

  1. 把新链表的首元结点的创建放在循环语句里面,并且在第一次创建新链表的结点时,把该结点赋给phead,并且所有操作都放在l1、l2结点数据相加之前
  2. 在循环语句末尾,给新链表的创建加上一条if语句,当l1、l2全为空指针,不再进行结点创建工作(笔者在此使用的)

4a886befb54f41dcb16ffdaa555f483c.png

        if(l1||l2) //只有两指针还有需要存入的数据再开辟新的空间,如果都已经存放完毕,那么就无需再开辟新的
        {
        newnode->next=buynode(0);
        newnode=newnode->next;
        }

解法1全部代码展示:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode listnode;
listnode* buynode(int x)
 {
    listnode* newnode = (listnode*)malloc(sizeof(listnode));
    newnode->val = x;
    newnode->next = NULL;
    return newnode;
}
                                    //l1首元结点指针      //l2首元结点指针
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) 
{
    int count=0;
    listnode* newnode=buynode(0); //创建一个新链表的首元结点
    listnode* phead=newnode;
    while(l1||l2) //退出条件为两个指针全为空
    {
        if(l1&&l2) //两指针都非空
        {
        //分为l1+l2 <=9 以及 l1+l2 >=10 两种情况
        //<=9
                if((l1->val)+(l2->val)+count<=9) 
        {
            newnode->val=(l1->val)+(l2->val)+count;
            count=0;
        }
        //>=10
        else
        {
            newnode->val=(l1->val)+(l2->val)+count-10;
            count=1;
        }
            l1=l1->next;
            l2=l2->next; 
        }
        else if(l1) //l1还不为空的情况
        {
            if((l1->val)+count<=9)
            {
                newnode->val=(l1->val)+count;
                count=0;
            }
            else
            {
            newnode->val=(l1->val)+count-10;
            count=1;
            }
             l1=l1->next; //为防止对空指针l2进行解引用操作
            }    
            else if(l2) //l2还不为空的情况
            {
            if((l2->val)+count<=9)
            {
                newnode->val=(l2->val)+count;
                count=0;
            }
            else
            {
            newnode->val=(l2->val)+count-10;
            count=1;
            }
             l2=l2->next; //为防止对空指针l1进行解引用操作
            }    
        if(l1||l2) //只有两指针还有需要存入的数据再开辟新的空间,如果都已经存放完毕,那么就无需再开辟新的
        {
        newnode->next=buynode(0);
        newnode=newnode->next;
        }
    }
        if(count==1) //两个指针全都为空但count还是为1,是对示例3的解决
        {
        newnode->next=buynode(1); //直接在newnode指针最后面加上一个结点,且最后一个结点数据域只可能为1
        }
    return phead;
}

1eb04a4521f04ef3be2c8e8d44f01e2a.png


解法2(优秀代码):
 

下面的代码是leetcode官方给的C语言题解,好漂亮的代码!

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2) {
    struct ListNode *head = NULL, *tail = NULL;
    int carry = 0;
    while (l1 || l2) {
        int n1 = l1 ? l1->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;
        } else {
            tail->next = malloc(sizeof(struct ListNode));
            tail->next->val = sum % 10;
            tail = tail->next;
            tail->next = NULL;
        }
        carry = sum / 10;
        if (l1) {
            l1 = l1->next;
        }
        if (l2) {
            l2 = l2->next;
        }
    }
    if (carry > 0) {
        tail->next = malloc(sizeof(struct ListNode));
        tail->next->val = carry;
        tail->next->next = NULL;
    }
    return head;
}

上述代码解释:

官方题解也是通过创建一个新链表,然后解决问题

首先创建了两个指针,一个指向了首元结点(用作返回),一个指向了尾元结点(用作存放数据);carry和我代码中的count一样,都是保存多出来的那个1的

循环语句退出条件、分支语句的写法此处省略

l1 ? l1->val : 0 --->该操作符的作用:l1不为空指针,就留下l1的值;l1为空指针,就留下0

l2 ? l2->val : 0 --->作用同上

sum:就是l1、l2的结点数据(还有carry)相加后结果

!head:如果头指针为空指针为真(首元结点的创建,和首元结点地址的保留)

sum%10:对10取余

sum/10:整型相除

进行完对新链表的赋值操作以后,让新链表的尾元结点指针指向空指针,等待下一次使用

最后如果carry依旧为1,那么再开辟一个结点空间存放,最后返回head指针

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1719545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端Vue小兔鲜儿电商项目实战Day05

一、登录 - 整体认识和路由配置 1. 整体认识 登录页面的主要功能就是表单校验和登录退出业务 ①src/views/Login/index.vue <script setup></script><template><div><header class"login-header"><div class"container m-…

【React】封装一个好用方便的消息框(Hooks Bootstrap 实践)

引言 以 Bootstrap 为例&#xff0c;使用模态框编写一个简单的消息框&#xff1a; import { useState } from "react"; import { Modal } from "react-bootstrap"; import Button from "react-bootstrap/Button"; import bootstrap/dist/css/b…

根据状态转移图实现时序电路 (三段式状态机)

看图编程 * ** 代码 module seq_circuit(input C ,input clk ,input rst_n,output wire Y ); reg [1:0] current_stage ; reg [1:0] next_stage ; reg Y_reg; //输出//第一段 &#xff1a; 初始化当前状态和…

TensorFlow Playground神经网络演示工具使用方法详解

在现代机器学习领域,神经网络无疑是一个重要的研究方向。然而,对于许多初学者来说,神经网络的概念和实际操作可能显得相当复杂。幸运的是,TensorFlow Playground 提供了一个交互式的在线工具,使得我们可以直观地理解和实验神经网络的基本原理。在这篇博客中,我们将详细介…

Spring Boot 项目中使用 JSP

文章目录 Spring Boot 项目中使用 JSP项目结构引入依赖包编写页面和后台运行方式一&#xff1a;Maven 命令运行方式二&#xff1a;在 IDEA 中运行方式三&#xff1a;打 war 包部署运行 Spring Boot 项目中使用 JSP 在 Spring Boot 项目中不是不可以使用 JSP 。想在 Spring Boo…

Fully Convolutional Networks for Semantic Segmentation--论文笔记

论文笔记 资料 1.代码地址 2.论文地址 https://arxiv.org/abs/1411.4038 3.数据集地址 论文摘要的翻译 卷积网络是强大的视觉模型&#xff0c;可以产生特征层次结构。我们表明&#xff0c;卷积网络本身&#xff0c;经过端到端&#xff0c;像素对像素的训练&#xff0c;在…

【NPS】微软NPS配置802.1x,验证域账号,动态分配VLAN(有线网络篇)

上两篇中介绍了如何配置NPS和在WLC上如何配置802.1X来实现验证域账号和动态分配VLAN&#xff0c;802.1x协议作为一种成熟的身份验证框架&#xff0c;不仅适用于无线网络&#xff0c;同样也适用于有线网络环境。这里我们将介绍如何在有线网络中部署802.1x认证&#xff0c;以验证…

IDEA调试前端html报错

IDEA调试前端html报错 报错如下&#xff1a; Waiting for connection to localhost:59004. Please ensure that the browser was started successfully with remote debugging port opened. Port cannot be opened if Chrome having the same User Data Directory is already …

代码随想录算法训练营第三十二 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 讲解链接&#xff1a;https://programmercarl.com/1005.K%E6%AC%A1%E5%8F%96%E5%8F%8D%E5%90%8E%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E6%95%B0%E7%BB%84%E5%92%8C.html 简单思路&#xff1a;逐个计算连续两天的股票差值&#xff0c;sum初始为零&…

今日学会的,刘姥姥进大观园

Git - First-Time Git Setup 下载了Git&#xff0c;会用Git了&#xff1f; 还有这个&#xff1a;学习 HTML5 Canvas 这一篇文章就够了 | 菜鸟教程 (runoob.com) JavaScript 用法 | 菜鸟教程 (runoob.com) 看到这个真的是受益匪浅&#xff0c;我终于懂了一直有的疑惑。 3D可…

生产问题(十六)数据丢失-mysql binlog排查

一、引言 最近作者遇到一个线上问题&#xff0c;是mysql 的数据丢失了&#xff0c;这里记录一下排查过程和binlog的分析。 二、问题 问题出现的表象是应用系统大量报错&#xff0c;各种空指针之类的&#xff0c;这种一看就不可能是代码发布的问题&#xff0c;原因一定在框架、…

springboot+vue 社区养老服务系统

Springbootvue社区居家养老服务系统&#xff0c;数据库mysql&#xff0c;mybatis框架&#xff0c;有可视化页面。 功能&#xff1a; 用户管理 养老服务管理 护理人员管理 服务类型管理 健康状况管理 社区管理 服务区管理 娱乐资讯管理 咨询分类管理 反馈建议 系统简历管理 轮播…

华为telnet的两种认证方式

华为telnet的两种认证方式 实验拓扑&#xff1a; 实验要求&#xff1a; 1.采用普通密码认证实现telnet 远程登录机房设备R3 2.采用AAA认证服务方式实现telnet 远程登录机房设备R3 实验步骤&#xff1a; 1.完成基本配置&#xff08;设备接口配置IP&#xff0c;此步骤略过&#…

2024上海中小学生古诗文大会方案已发布,家长孩子最关心10个问题

昨天&#xff08;2024年5月30日&#xff09;下午15点&#xff0c;上海中小学生古诗文大会组委会通过两个公众号发布了《2024上海中小学生古诗文大会系列活动方案出炉》的推文&#xff08;下称《方案》&#xff09;。如我之前的分析和预测&#xff0c;5月份会发布今年的中小学生…

【如何用爬虫玩转石墨文档?】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

机器人动力学模型与MATLAB仿真

机器人刚体动力学由以下方程控制&#xff01;&#xff01;&#xff01; startup_rvc mdl_puma560 p560.dyn 提前计算出来这些“disturbance”&#xff0c;然后在控制环路中将它“抵消”&#xff08;有时候也叫前馈控制&#xff09; 求出所需要的力矩&#xff0c;其中M项代表克服…

判断自守数-第13届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第75讲。 判断自守数&#…

【Qt秘籍】[006]-Qt 的 Hello World程序-编程第一步

"Hello,World!" 中文意思是“你好&#xff0c;世界”。 因为 The C Programming Language 中使用它做为第一个演示程序&#xff0c;后来很多程序员在学习编程或进行设备调试时延续了这一习惯。 下面&#xff0c;我们也将演示Qt中的"Hello World!" 我们先创…

分享一个 ASP.NET Web Api 上传和读取 Excel的方案

前言 许多业务场景下需要处理和分析大量的数据&#xff0c;而 Excel 是业务人员常用的数据表格工具&#xff0c;因此&#xff0c;将 Excel 表格中内容上传并读取到网站&#xff0c;是一个很常见的功能&#xff0c;目前有许多成熟的开源或者商业的第三方库&#xff0c;比如 NPO…

计算机视觉与模式识别实验1-2 图像的形态学操作

文章目录 &#x1f9e1;&#x1f9e1;实验流程&#x1f9e1;&#x1f9e1;1.图像膨胀2.图像腐蚀3.膨胀与腐蚀的综合使用4.对下面二值图像的目标提取骨架&#xff0c;并分析骨架结构。 &#x1f9e1;&#x1f9e1;全部代码&#x1f9e1;&#x1f9e1; &#x1f9e1;&#x1f9e1…