复习leetcode第二题:两数相加

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

下图是题目

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指针

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JS红宝书学习笔记】第6章 集合引用类型

第6章 集合引用类型 对象 数组与定型数组 Map、WeakMap、Set 以及 WeakSet 类型 1. object 很适合存储和在应用程序间交换数据。 显式创建object的两种方式&#xff1a; &#xff08;1&#xff09;new操作符 let person new Object(); person.name "Nicholas";…

nginx的安装001

Nginx是一款高性能的HTTP和反向代理服务器&#xff0c;以及邮件代理服务器&#xff0c;由 Igor Sysoev 开发并公开发布于2004年。Nginx以其高并发处理能力、低内存消耗和稳定性著称&#xff0c;特别适合部署在高流量的网站上。 操作系统&#xff1a; CentOS Stream 9 安装步骤…

CentOS7配置国内清华源并安装docker-ce以及配置docker加速

说明 由于国内访问国外的网站包括docker网站&#xff0c;由于种种的原因经常打不开&#xff0c;或无法访问&#xff0c;所以替换成国内的软件源和国内镜像就是非常必要的了&#xff0c;这里整理了我安装配置的基本的步骤。 国内的软件源有很多&#xff0c;这里选择清华源作为…

官方小游戏项目

一 项目原理&#xff1a;看广告&#xff0c;操作简单&#xff0c;时间自由&#xff0c;适合利用业余时间来做&#xff0c;一个广告大概在15s-30s之间。 二 介绍&#xff1a;给你开代理权限&#xff0c;你就有独立后台管理系统&#xff0c;监测每台手机每条广告的情况&#xff0…

案例研究|MeterSphere助力万物云构建高效自动化测试平台

万物云空间科技服务股份有限公司&#xff08;以下简称为“万物云”&#xff09;&#xff0c;前身为万科物业发展股份有限公司&#xff0c;是国内领先的物管龙头上市公司。作为一家科技引领的全域空间服务商&#xff0c;万物云致力于打造产业级共享服务平台&#xff0c;基于空间…

【qt】自定义对话框

自定义对话框 一.自定义对话框的使用1.应用场景2.项目效果3.界面拖放4.模型和视图的设置5.action功能实现 二.自定义对话框的创建1.设置对话框界面2.创建对话框 三.对话框的功能与样式实现1.对话框数据的交换2.对话框的显示3.设置对话框的特性4.完成按钮的功能 四.编辑表头的对…

根据PDF模版填充数据并生成新的PDF

准备模版 使用 福昕高级PDF编辑器 &#xff08;本人用的这个&#xff0c;其他的也行&#xff0c;能作模版就行&#xff09;打开PDF文件点击 表单 选项&#xff0c;点击 文本域在需要填充数据的位置设计文本域设置 名称、提示名称相当于 属性名&#xff0c;提示就是提示&#x…

Docker的数据管理(数据卷+数据卷容器)

文章目录 一、Docker的数据管理1、概述2、主要的技术&#xff08;三种数据挂载方式&#xff09;2.1、数据卷&#xff08;Volumes&#xff09;2.2、绑定挂载&#xff08;Bind mounts&#xff09;2.3、tmpfs挂载&#xff08;Tmpfs mounts&#xff09;2.4、之间的关系&#xff08;…

移动端性能测试(android/ios)

solox官网 https://github.com/smart-test-ti/SoloX solox简介 实时收集android/ios性能的工具&#xff0c;Android设备无需Root&#xff0c;iOS设备无需越狱。有效解决Android和iOS性能的测试和分析挑战。 solox安装 环境准备 python安装3.10以上的 python官网下载地址…

CasaOS:开源家庭云系统安装

CasaOS是一个基于Docker生态系统的开源家庭云系统&#xff0c;专为家庭场景而设计。致力于打造全球最简单、最易用、最优雅的家居云系统。安装CasaOS可以给鲁班猫带来更好的局域网文件传输体验。 安装脚本 wget -qO- https://get.casaos.io | sudo bash软件截图

【论文复现|智能算法改进】基于自适应蜣螂算法的无人机三维路径规划方法

目录 1.UAV路径规划数学模型2.改进点3.结果展示4.参考文献5.代码获取 1.UAV路径规划数学模型 【智能算法应用】蜣螂优化算法DBO求解UAV路径规划 2.改进点 混沌序列初始化 在处理复杂的优化问题时&#xff0c;原始蜣螂算法采用随机生成种群的方法进行种群初始化&#xff0c;…

【Qt知识】Qt Creator快捷键

以下是Qt Creator中的一些常用快捷键列表&#xff08;持续更新&#xff09;&#xff1a; 基本编辑 多行注释/取消多行注释: Ctrl /编译工程: Ctrl B运行工程: Ctrl R整行上移/下移: Ctrl Shift ↑/↓查找: Ctrl F函数声明和定义切换: F2向下查找: F3头文件和源文件切换:…

Docker安装Zookeeper(单机)

Docker安装Zookeeper&#xff08;单机&#xff09; 目录 Docker安装Zookeeper&#xff08;单机&#xff09;拉取镜像创建目录添加配置文件启动容器测试 拉取镜像 docker pull zookeeper创建目录 mkdir -p /data/zookeeper/data # 数据挂载目录 mkdir -p /data/zookeeper/conf…

03-树1 树的同构(浙大数据结构PTA习题)

03-树1 树的同构 分数 25 作者 陈越 单位 浙江大学 给定两棵树 T1​ 和 T2​。如果 T1​ 可以通过若干次左右孩子互换就变成 T2​&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G…

基于朴素贝叶斯算法的新闻类型预测,django框架开发,前端bootstrap,有爬虫有数据库

背景 在当今信息爆炸的时代&#xff0c;新闻内容的分类和预测对于用户个性化推荐和信息检索至关重要。基于朴素贝叶斯算法的新闻类型预测系统结合了机器学习和自然语言处理技术&#xff0c;能够根据新闻内容自动进行分类&#xff0c;提高新闻处理效率和准确性。采用Django框架…

Spring MVC 应⽤分层

什么是应用分层 引用分层是一种软件开发思想 将应用程序分为N个层次每个层次负责各个职责 其中MVC是常见的设计模式这就是应用分层的具体体现 目前主流的开发方式是前后段分离后端开发工程师不再需要关注前端的实现,对此就需要分为表现层&#xff0c;数据层&#xff0c;业务逻…

RxSwift - 实现一个MVVM架构的TableView

文章目录 RxSwift - 实现一个MVVM架构的TableView前沿MVVM架构的Tableview目录结构1、模型&#xff08;Model&#xff09;2、视图模型&#xff08;ViewModel&#xff09;3、视图&#xff08;View&#xff09; 界面效果 RxSwift - 实现一个MVVM架构的TableView 前沿 MVVM架构在…

IBM开源Granite Code模型,多尺寸可选,支持多种代码任务,性能媲美 CodeLlama

前言 近年来&#xff0c;大型语言模型&#xff08;LLM&#xff09;在代码领域展现出惊人的潜力&#xff0c;为软件开发流程带来了革命性的改变。代码 LLM 不仅能够生成高质量代码&#xff0c;还能帮助程序员修复错误、解释代码、编写文档等等&#xff0c;极大地提高了软件开发…

MyBatis通用Mapper:简化数据库操作的利器

引言 在软件开发中&#xff0c;数据库操作是不可或缺的一部分。通常我们会使用mybatis&#xff0c;的MBG插件&#xff0c;自动生成表对应的基本操作语句xml。 当我们的表字段发生变化的时候&#xff0c;我们需要修改实体类和Mapper文件定义的字段和方法。如果是增量维护&…

为何ICLR未能进入CCF推荐期刊会议列表?

会议之眼 快讯 最近小编在思考一个问题&#xff1a;ICLR&#xff08;International Conference on Learning Representations&#xff09;即国际学习表征会议自2013年诞生以来&#xff0c;ICLR以其开放的学术氛围、创新的研究议题和前沿的科学探索&#xff0c;迅速成为AI领域不…