首页 > 其他分享 >链表【两数相加】具体思路——【递归】【迭代】【暴力】(附完整代码)

链表【两数相加】具体思路——【递归】【迭代】【暴力】(附完整代码)

时间:2024-10-10 18:19:02浏览次数:3  
标签:ListNode 迭代 递归 int nullptr next 链表 l2 l1

文章目录


前言

本文将介绍【链表】两数相加

对于这一问题将采用多种思路方法来解决

【暴力】【递归法】【迭代法】


一、问题引入,如何理解【链表】两数相加?

题目链接: [点击跳转] Leetcode 2. 两数相加

题目如下:

请添加图片描述

给出两个链表,两链表分别表示两个逆序整数,计算两整数之和,并输出所对应的逆序链表。

那么,根据题目,我们发现在代码实现时需要注意以下内容:

1.给出的两个链表为非空链表,但可能均只有一个节点0。

2.给出的两个链表的长度可能相同,也可能不同。

3.本题所给链表的节点数不超过100。


二、方法一(固定数组暴力)

对于本题而言,我们将其逻辑理解为:将两链表所表示的数,加和,然后输出为链表。

因此,我们可以考虑如何将两链表里各个节点的元素取出,并按逆序排列成真正的数。

如下:

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* tre=new ListNode(0);
        int a[100]={0};
        int b[100]={0};
        ListNode* pre=tre;
        if(l1==nullptr&&l2==nullptr){
            return nullptr;
        }
        for(int i=0;l1!=nullptr;i++){
            a[i]=l1->val;
            l1=l1->next;
        }
        for(int j=0;l2!=nullptr;j++){
            b[j]=l2->val; 
            l2=l2->next; 
        }
    }
};

在这一步中,我们成功地将链表里的数导入到数组中。

(这里我们直接定义的是固定数组,因为我们提前已知了节点数的范围不会超过100。)

接下来,我们需要实现两数相加。

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        vector<int> sum;//计算加和
        int a[100]={0};
        int b[100]={0};
        int s=0;
        ListNode* pre=tre;
        if(l1==nullptr&&l2==nullptr){//排除空节点干扰
            return nullptr;
        }
        for(int i=0;l1!=nullptr;i++){
            a[i]=l1->val;
            l1=l1->next;
        }
        for(int j=0;l2!=nullptr;j++){
            b[j]=l2->val; 
            l2=l2->next; 
        }
        for(int x=0;x<100;x++){//求sum
            if(a[x]+b[x]<10){//如果同一位上的两个数相加<10,则无需进位
                sum.push_back(a[x]+b[x]);
            }else{//进位,下一位+1
                sum.push_back(a[x]+b[x]-10);
                a[x+1]+=1;
            }
        }
};

最后我们将得到的这个向量sum按照链表逆序输出即可。

注意:这里的节点数范围在[0,100],因此我们不得不用vector来存储两数之和,不可以用long long类型来储存,否则会超出long long范围。

完整代码如下:

/**
 * 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* tre=new ListNode(0);
        vector<int> sum;
        int a[100]={0};
        int b[100]={0};
        int s=0;
        ListNode* pre=tre;
        if(l1==nullptr&&l2==nullptr){
            return nullptr;
        }
        for(int i=0;l1!=nullptr;i++){
            a[i]=l1->val;
            l1=l1->next;
        }
        for(int j=0;l2!=nullptr;j++){
            b[j]=l2->val; 
            l2=l2->next; 
        }
        for(int x=0;x<100;x++){//求sum
            if(a[x]+b[x]<10){
                sum.push_back(a[x]+b[x]);
            }else{
                sum.push_back(a[x]+b[x]-10);
                a[x+1]+=1;
            }
        }
        while (!sum.empty() && sum.back() == 0) {
            sum.pop_back();
        }
        if(sum.empty()){
            return tre;
        }
        while(!sum.empty()) {
            int m = sum.front();
            pre->next = new ListNode(m);
            pre = pre->next;
            sum.erase(sum.begin());
        }
        return tre->next;

    }
};

三、方法二(递归法)

在使用暴力的方法定义固定数组后,我们发现在面对节点数很少的节点,我们会无意义地将整个数组遍历出来,并且最后还需要将多余的0去除。

那么我们可不可以想到更好的方法呢?

在这里,我们可以尝试一下高贵的递归法。

首先,我们需要考虑递归的内容,很清晰:我们需要将两个链表对应元素都需要相加。

那么我们就可以明确递归的内容了,输入两节点,计算节点值之和并记录下来。

代码如下:

class Solution {
public:
    ListNode* tre = new ListNode(0);
    void addnode(ListNode* l1, ListNode* l2, int carry) {
        if (l1 == nullptr && l2 == nullptr && carry == 0) return;
        int val = (l1? l1->val : 0) + (l2? l2->val : 0) + carry;
        ListNode* newNode = new ListNode(val%10);//保证传入节点的值小于10
        ListNode* current = tre;
        while (current->next!= nullptr) {//循环找到尾节点
            current = current->next;
        }
        current->next = newNode;// 将新节点连接到结果链表上
        addnode(l1?l1->next:nullptr,l2?l2->next:nullptr,val/10);//递归,传入进位
    }
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        addnode(l1, l2, 0);
        return tre->next;
    }
};

首先在主函数addTwoNumber传进来所给的两个链表头节点。

然后我们将这两个节点扔进我们的递归函数addnode中,同时传进一个carry,这个carry表示进位,如果传入0,表示无需进位,传入1,表示进1位。在第一次进入递归函数时,初始化为0。

并且需要在递归函数中创建节点,同时连接节点,最后递归函数结束后,链表也就完成啦!


四、方法三(迭代法)

经过上述两种方法后,我们发现,在方法一中无需使用递归函数,方法二中对于节点值的处理更加简单。我们可以尝试将两者的优点集中起来。

我们可以继续沿用carry来帮助我们计算进位,同时直接在while循环中创建节点并连接成链表。

代码如下:

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode();
        ListNode* cur = head;//用cur来操作链表
        int carry = 0;//表示进位
        while (l1 || l2 || carry) {//全为0才跳出循环
            int sum = (l1? l1->val : 0) + (l2? l2->val : 0) + carry;//计算和
            cur->next = new ListNode(sum % 10);//新建节点,并连接
            carry = sum/10;//计算是否进位
            cur = cur->next;//移向下一个
            l1 = l1? l1->next : nullptr;//判断并移动
            l2 = l2? l2->next : nullptr;
        }
        return head->next;
    }
};

需要注意的是,当l1,l2,carry全为0,说明后续无数,并且不会继续向前进位,这时我们才完成了所有计算。


标签:ListNode,迭代,递归,int,nullptr,next,链表,l2,l1
From: https://blog.csdn.net/bufangbufang/article/details/142813279

相关文章

  • 快速排序的非递归实现:借助栈实现、借助队列实现
    目录用栈实现快速排序1.用栈实现非递归快速排序的思路步骤1.1.思路步骤2.用栈实现非递归快速排序的代码3.用栈实现非递归快速排序的整个工程3.1.QuickSortNonR.h3.2.QuickSortNonR.c3.3.Stack.h3.4.Stack.c用队列实现非递归快速排序1.用队列实现非递归快速排序的思......
  • 详解二叉树的非递归遍历
    二叉树的非递归遍历:二叉树的非递归遍历使用栈或队列自身功能(先进后出或先进先出)来实现。对于非常深的树,递归可能导致栈溢出错误,因为每次递归调用都会占用栈空间。非递归遍历使用显式的栈或队列,可以更好地控制内存使用,避免这种问题。链表节点:classTreeNode{intv......
  • STL——3.迭代器
     1.迭代器的基本概念作用:迭代器是用于遍历容器元素的对象。分类:输入迭代器输出迭代器前向迭代器双向迭代器随机访问迭代器2.迭代器的用法2.1输入迭代器#include<iostream>#include<iterator>#include<vector>intmain(){std::cout<<"Enterintegerssep......
  • Linkedlist链表
    目录1.ArrayList的缺陷2.链表2.1链表的概念及结构2.2链表结构2.2.1头插法2.2.2删除元素2.2.3清空方法(clear方法)2.2.4修改元素2.3.单链表的优化1.功能接口2.功能实现3.其他处理1.ArrayList的缺陷上节课已经熟悉了ArrayList的使用,并且进行了简单模拟......
  • 编写一个程序递归判断一个字符串是否为回文。回文是指从前往后读和从后往前读都一样的
    defis_string_palindrome(string):iflen(string)<2:#设置出口returnTrueelse:#判断首末位是否相同ifstring[0]==string[len(string)-1]:#用列表来删除首末位相同字符list1=list(string)list1.pop(0)list1.pop()string=''.join(list1)#设置过程returnis_str......
  • 递归下降--自顶向下的解析方法
    递归下降(RecursiveDescentParsing)是一种自顶向下的解析方法,用于解析编程语言的语法或表达式。它通过使用一组递归的函数来处理文法规则(通常是上下文无关文法),从而将输入字符串解析为语法树或抽象语法树(AST)。递归下降解析器是手工编写的,因此可以根据具体需要灵活地控制解析行为......
  • 数据结构(链表)
    我可以接受失败,但绝对不能接受未奋斗过的自己。   链表链表的概念1.链表是⼀种物理存储结构上非连续、非顺序的存储结构。2.链表是顺序表的一种,所以它一定在逻辑结构上是线性的。3.数据元素的逻辑顺序是通过链表中的指针链接次序实现的。4.链表实际上由一个......
  • c++单链表(带头结点)
    #include<iostream>usingnamespacestd;//定义typedefstruct_LinkNode{  intdata;//结点的数据域  struct_LinkNode*next;//结点的指针域}LinkNode,Linklist;//初始化boolInitList(Linklist*&L){  L=newLinkNode;  if(!L)returnfalse; ......
  • 链表Set_LinkList(建立)
    用单链保存集合元素,元素由键盘输入。输入以-1结束,将所建链表打印输出。链表结构如下图所示:提示:1.链表中数据元素为整型,typedef int ElemType;2.用结构体自定义链表结构Set_LinkList ;3.初始化链表函数init(),该函数可创建空链表L,返回L的头指针地址;4.链表插入结点函数......
  • JS刷力扣-链表【持续跟新】
    力扣的链表归类2.两数相加【链表+递归】前置知识:1.链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。2.链表的入口节点称为链表的头结点也就是head。leet......