LeetCode2. 两数相加

news2024/11/16 17:59:49

写在前面:

题目链接:LeetCode2两数相加
编程语言:C++
题目难度:中等

一、题目描述

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

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

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
在这里插入图片描述

输入: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 常规老实人解法

解之前先吐槽一番,计算两个数相加的结果,给个单向链表也就算了,存的还是数字的反序,意味着本来要计算,123+23,还得
先将链表遍历一遍

3->2->1
3->2

反序一次得到正序 (后面才意识到不用反序)

1,2 ,3
2,3

接下来就开始进行
加法运算

要么先将 1,2 ,3 和2,3 先转换为 123、23 ,然后计算得出结果为 146,然后再逐一的进行再把每一位取出来,并且按照逆序 构建成 一个 6->4->1 单向链表再返回回去;

要么直接进行按位相加,自己设计进位,最后 组成 6,4,1 这样有一个序列然后构建链表,再返回。

各位献丑了,且看我写了半小时的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* listResult = new ListNode();
    vector<int> vct1;
    vector<int> vct2;
    ListNode* nodeTemp = l1;
    //先将l1、l2遍历一遍
    while(nodeTemp != nullptr)
    {
        vct1.push_back(nodeTemp->val);
        nodeTemp = nodeTemp->next;
    }
    ListNode* nodeTemp1 = l2;
    while(nodeTemp1 != nullptr)
    {
        vct2.push_back(nodeTemp1->val);
        nodeTemp1 = nodeTemp1->next;
    }
    vector<int> vctResult;

    int i = 0;
    int j = 0;
    int iTemp = 0;
    bool isTen = false;//是否进位
    //开始按位相加 从 个位开始
    while(i<vct1.size() && j<vct2.size())
    {
        iTemp = vct1[i] + vct2[j];
        if(isTen)
        {
            iTemp +=1;
        }
        if(iTemp >= 10)
        {
            isTen = true;
            iTemp = iTemp -10;
        }   
        else
        {
            isTen = false;
        }      
        vctResult.push_back(iTemp);
        i++;
        j++;
    }
    //两个链表长度不相等,那么剩下的直接继续按位加即可
    while( i <vct1.size())
    {
        if(isTen)//注意上一个while 后可能还有进位 1
        {
            if(vct1[i] + 1 ==10)//继续进位
            {
                vctResult.push_back(0);
                isTen = true;
            }
            else
            {
                vctResult.push_back(vct1[i]+1);
                isTen = false;
            }
            i++;
        }
        else
        {
            //没有进位直接插入即可
            vctResult.push_back(vct1[i]);
            i++;
        }
    }
    //同理将剩下的都插入,和上面进位机制一样
    while( j< vct2.size())
    {
        if(isTen)
        {
            if(vct2[j] + 1 ==10)
            {
                vctResult.push_back(0);
                isTen = true;
            }
            else
            {
                vctResult.push_back(vct2[j]+1);
                isTen = false;
            }
            j++;
        }
        else
        {
            vctResult.push_back(vct2[j]);
            j++;
        }
    }
    if(isTen)//注意可能最后还有一次进位
    {
        vctResult.push_back(1);
    }
    //接下来构建出链表
    bool head = true;
    ListNode* nodenext = new ListNode();
    for(int k = 0; k < vctResult.size();k++)
    {
        ListNode* node = new ListNode();
        node->val = vctResult[k];
        node->next = nullptr;
        if(head)
        {
            listResult = node;//保存头,做返回值返回
            nodenext = node;
            head = false;
        }
        else
        {
            nodenext->next = node;
            nodenext = nodenext->next;
        }
    }
    return listResult;

    }
};

运行结果:
跑了几次好一点的就是下面这样了
在这里插入图片描述

2.1.2 优化后

写道最后,才发现不需要用两个vector 遍历,直接遍历链表即可,我们常固性思维觉得加法就是这样:
在这里插入图片描述
其实我们做个镜像对比:
在这里插入图片描述
这不就是我们刚好要的答案吗?
因此我们现在直接简化为:
遍历两个链表

3 -> 2 -> 1
3->2

将刚才的代码额外的两次遍历与两个vector 开辟 干掉:

在这里插入图片描述

直接做进位的加法,我们将上述的代码优化为:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* listResult = new ListNode();
    ListNode* nodeTemp = l1;
    ListNode* nodeTemp1 = l2;
    vector<int> vctResult;
    int i = 0;
    int j = 0;
    int iTemp = 0;
    bool isTen = false;//是否进位
    //开始按位相加 从 个位开始
    while(nodeTemp!=nullptr && nodeTemp1!=nullptr)
    {
        iTemp = nodeTemp->val + nodeTemp1->val;
        if(isTen)
        {
            iTemp +=1;
        }
        if(iTemp >= 10)
        {
            isTen = true;
            iTemp = iTemp -10;
        }   
        else
        {
            isTen = false;
        }      
        vctResult.push_back(iTemp);
        nodeTemp = nodeTemp->next;
        nodeTemp1 = nodeTemp1->next;
    }
    //两个链表长度不相等,那么剩下的直接继续按位加即可
    while( nodeTemp!= nullptr)
    {
        if(isTen)//注意上一个while 后可能还有进位 1
        {
            if(nodeTemp->val + 1 ==10)//继续进位
            {
                vctResult.push_back(0);
                isTen = true;
            }
            else
            {
                vctResult.push_back(nodeTemp->val+1);
                isTen = false;
            }
            nodeTemp=nodeTemp->next;
        }
        else
        {
            //没有进位直接插入即可
            vctResult.push_back(nodeTemp->val);
            nodeTemp=nodeTemp->next;;
        }
    }
    //同理将剩下的都插入,和上面进位机制一样
    while( nodeTemp1 != nullptr)
    {
        if(isTen)
        {
            if(nodeTemp1->val + 1 ==10)
            {
                vctResult.push_back(0);
                isTen = true;
            }
            else
            {
                vctResult.push_back(nodeTemp1->val+1);
                isTen = false;
            }
            nodeTemp1 = nodeTemp1->next;
        }
        else
        {
            vctResult.push_back(nodeTemp1->val);
            nodeTemp1 = nodeTemp1->next;
        }
    }
    if(isTen)//注意可能最后还有一次进位
    {
        vctResult.push_back(1);
    }
    //接下来构建出链表
    bool head = true;
    ListNode* nodenext = new ListNode();
    for(int k = 0; k < vctResult.size();k++)
    {
        ListNode* node = new ListNode();
        node->val = vctResult[k];
        node->next = nullptr;
        if(head)
        {
            listResult = node;//保存头,做返回值返回
            nodenext = node;
            head = false;
        }
        else
        {
            nodenext->next = node;
            nodenext = nodenext->next;
        }
    }
    return listResult;

    }
};

在这里插入图片描述
可以看到时间和空间上都有所优化。

但是可以看到整个代码还是臭长臭长的,而且还开辟了一个新vector用于保存结果,空间复杂度也没有降低,还有没有更简介的写法呢?

2.3 写法简化&空间优化

之前还需要一个 bool 值来控制是否进位,每次还需要取余数等等,非常的繁琐
在这里插入图片描述
其实我们直接取两位和的个位数,为当前位的值,取 10 位上的数为进位即可
例如 5 + 9,

当前位为 14 % 10 = 4;
进位为:14 / 10 = 1;

而且之前会考虑链表长度不相等的情况,然后对余下的节点再做一次遍历,并且判断之前的进位:
在这里插入图片描述
换种思路,我们将空缺的部分补 上 0
在这里插入图片描述
这样来处理长度不一样的情况:

        int n1 = nodeTemp == nullptr ? 0: nodeTemp->val;
        int n2 = nodeTemp1 == nullptr ? 0:nodeTemp1->val;

完整代码示例:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* head = nullptr;
    ListNode* tail = nullptr;
    ListNode* nodeTemp = l1;
    ListNode* nodeTemp1 = l2;
    int igientle = 0;//进位
    //开始按位相加 从 个位开始
    while(nodeTemp!=nullptr || nodeTemp1!=nullptr)
    {
        //链表长度不够时补 0 ,
        int n1 = nodeTemp == nullptr ? 0: nodeTemp->val;
        int n2 = nodeTemp1 == nullptr ? 0:nodeTemp1->val;
        int temp = n1+n2+igientle;//两位的和再加上进位
        if(!head)//先将头节点保存好
        {
            head = new ListNode(temp % 10);//取余数
            tail = head;
        }  
        else{
            tail->next = new ListNode(temp%10);
            tail = tail->next;
        }
        igientle=temp/10;//进位   
        if(nodeTemp)
        {
            nodeTemp = nodeTemp->next;
        }
        if(nodeTemp1)
        {
            nodeTemp1 = nodeTemp1->next;
        }
    }
    if(igientle > 0)//最后还有进位时也加上
    {
        tail->next = new ListNode(igientle);
    }
    return head;

    }
};

运行结果:

在这里插入图片描述

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

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

相关文章

光学液氮恒温器T9120-4W的技术参数

液氮型低温恒温器&#xff0c;利用液氮作为降温媒介&#xff0c;标准恒温器可实现快速降温至液氮温度&#xff08;约20min&#xff09;&#xff0c;其工作原理是在恒温器内部液氮腔内装入液氮&#xff0c;通过调整控温塞与冷指的间隙来保持冷指的漏热稳定在一定值上&#xff0c…

lua实战(1)

目录 IDELua中的名称Lua是一种区分大小写的语言 Lua 是一个小巧的脚本语言。它是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo三人所组成的研究小组于1993年开…

vue3+electron开发桌面软件(9)——选中多个文件,右键上传

系列文章目录 系列第一篇&#xff1a; vue3electron开发桌面软件入门与实战&#xff08;0&#xff09;——创建electron应用 文章目录 系列文章目录前言一、我们如何思考二、解决问题1.选择方案2. 发现electron多开窗口监听3.查找可使用的官方参数4.示例代码 总结 前言 从本系…

Docker 安全及日志管理

Docker 安全及日志管理 Docker 容器与虚拟机的区别隔离与共享性能与损耗 Docker 存在的安全问题Docker 自身漏洞Docker 源码问题Docker 架构缺陷与安全机制Docker 安全基线标准 容器相关的常用安全配置方法容器最小化Docker 远程 API 访问控制重启 Docker在宿主机的 firewalld …

ASEMI代理ADI亚德诺ADXL345BCCZ-RL7车规级芯片

编辑-Z ADXL345BCCZ-RL7特点&#xff1a; 超低功率&#xff1a;在测量模式下低至23A 在VS2.5 V的待机模式下为0.1A&#xff08;典型&#xff09; 功耗会随带宽自动调整 用户可选分辨率 固定的10位分辨率 全分辨率&#xff0c;其中分辨率随着g范围的增加而增加&#xff0…

00后才是内卷之王,被卷的头皮发麻....

都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;前段时间我们公司来了个00年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。…

Redis主从复制(搭建集群的一种方式)【故障转移,内存,回收】

做一个伪集群 配置文件&#xff1a; daemonize yes port 7777 logfile .redis-7777.log dir ./ bind 0.0.0.0启动6666 and 7777 现在设置主从表 但是有个问题我把服务器停掉 关系就会解除 还可以手动解除 slaveof no one 命令 配置Sentinel&#xff08;哨兵&#…

基于络达SOC AB1562A TWS蓝牙耳机设计

V hezkz17进数字音频答疑 一 原理框图 二 电子电路设计 (1)SOC主芯片 (2) 最小系统晶振电路设计26MHZ (3) 电池电路设计 4 充电电路与充电保护设计 5 LED输出电路设计</

hexo stellar设置目录跳转记录

1. 使用hexo-toc插件 一开始使用的是hexo-toc的插件&#xff1a;参考hexo安装toc插件 详细的可以看github的项目&#xff1a; github-hexo-toc 更加详细的配置&#xff1a; Hexo添加Toc支持&#xff0c;生成文章目录 2. 官网的方式&#xff08;推荐&#xff09; stellar博…

flink cdc原理与使用

flink cdc原理与使用 1 cdc 介绍1.1 cdc简介与对比1.2 基于日志的 CDC 方案介绍 2 基于 Flink SQL CDC 的数据同步方案实践2.1 案例 1 : Flink SQL CDC JDBC Connector2.2 案例 2 : CDC Streaming ETL2.3 案例 3 : Streaming Changes to Kafka 3 Flink SQL CDC 的更多应用场景…

Java EE企业级应用开发(SSM)第10章

第10章MyBatis核心配置及动态SQL 一.预习笔记 1.第九章的细节处理 1-1.mappers标签中的配置 1-2.jdbc属性文件的配置 1-3.包的别名配置 2.Mybatis核心配置文件 2-1&#xff1a;settings标签&#xff08;P145-146中的表10-1&#xff09; 2-2.类型别名 3.Mybatis映射文件 3-1…

项目集管理绩效领域

项目集管理绩效领域是对活动或职能相关领域的补充分组&#xff0c;这些活动或职能在项目集管理工作的 整个范围内&#xff0c;专门描述和区分一个绩效领域中的活动。 本章包括&#xff1a; 项目集管理绩效领域的定义项目集管理绩效领域的交互组织战略、项目组合管理和项目集管…

vue 水印组件

效果图展示 Watermark 参数说明类型默认值版本width水印的宽度&#xff0c;content 的默认值为自身的宽度number120height水印的高度&#xff0c;content 的默认值为自身的高度number64rotate水印绘制时&#xff0c;旋转的角度&#xff0c;单位 number-22zIndex追加的水印元素…

24.eslint

eslint是约束代码写法的插件&#xff0c;比如组件的命名必须要用驼峰命名这种 eslint官网 检测并修复 JavaScript 代码中的问题。 - ESLint - 插件化的 JavaScript 代码检查工具 目录 1 vue-cli的eslint 2 标准规则 2.1 不能连续出现两个空行 2.2 结尾必须有空行 2.3…

深入了解Dubbo SPI 工作机制——@Activate (5)

在上一篇Dubbo 基于xml文件分析主流程源码 &#xff08;4&#xff09;_chen_yao_kerr的博客-CSDN博客中, 我们已经初步了解了Dubbo SPI的 key - value 结构。接下来将会继续分享Dubbo SPI其他功能的使用方式&#xff0c;并且从源码的角度去一谈究竟。 Activate注解 参数名 …

【数据结构】链表OJ:力扣141.环形链表、142.环形链表II

今天要分享的关于链表的题目是环形链表 目录 题目141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 题解 关于快慢指针的深入研究 题目2&#xff1a;142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; 题解 以下是题目链接 141. 环形链表 - 力扣&#xff…

塑料回收---未来化工行业的新兴增长领域

大量的旧塑料被浪费 从南极洲到北极&#xff0c;在原始海岸线上冲刷的塑料废物&#xff0c;以及太平洋上巨大的塑料废物浮岛&#xff0c;得到了媒体的广泛报道&#xff0c;并促成了消费者消费意识发生转变。 研究表明&#xff0c;大多数废旧塑料被送往垃圾填埋场和焚烧&#…

Go语言设计模式之责任链模式

其实很多人不知道,责任链模式是我们工作中经常遇到的模式,特别是web后端工程师,我们工作中每时每刻都在用:因为市面上大部分的web框架的过滤器基本都是基于这个设计模式为基本模式搭建的。 1.模式介绍 我们先来看一下责任链模式(Chain Of Responsibility Design Pattern…

react实现点击获取json对象的jsonPath

准备 安装 react-json-view&#xff1a;npm install --save react-json-view 可参考的一些开源库&#xff1a;react-json-path-picker&#xff0c;json-path-picker 线上工具&#xff1a;jsonpath tool JsonPath JsonPath官方文档 用来解析多层嵌套的json数据。JsonPath 是一…

8分钟的面试,我直呼太变态了......

干了两年外包&#xff0c;本来想出来正儿八经找个互联网公司上班&#xff0c;没想到算法死在另一家厂子。 自从加入这家外包公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以也就忍了。没想到11月一纸通知&#xff0c;所有人不许加班&#xff0c;薪资…