【LeetCode】|【 C++学习】2.两数相加 - 链表理解+NULL、nullptr 、0 的区别



题目

\quad \quad 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

在这里插入图片描述

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/add-two-numbers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


一、所需知识

  1. ListCode 链表

ListCode是一个链表结构。它由 当前节点数据+指向下一个节点数据的指针组成。如下图
在这里插入图片描述
基于此, 节点ListCode的结构定义:
(需要具备两个基本属性:一个是当前节点的值,一个是下一个节点的ListNode类型的值。)

#include
 struct ListNode 
{
// 两个基本属性
    int val;          // 当前节点的数据
    ListNode *next;   // 下一个节点的地址
// 还可以加上 构造函数
    ListNode() : val(0), next(nullptr) {}    // 设置当前节点的值为 0,下一个节点的地址为空。
    ListNode(int x) : val(x), next(nullptr) {}   // 将x的值赋给当前节点,下一个节点地址为空。     
    ListNode(int x, ListNode *next) : val(x), next(next) {} // // 将x的值赋给当前节点,下一个节点地址为next。
};
// 假如说要定义[2, 4, 6]这么一个链表,也可以这么赋值,这样我感觉会更清晰的理解到链表的结构。
ListNode l1 = new ListNode(2, new ListNode(4, new ListNode(6)));
  1. NULL、nullptr 、0 的区别

在这里插入图片描述

二、解题

代码如下(力扣LeetCode):

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* Nl1, ListNode* Nl2)
    {
        // 首先定义两个链表,分别存放 链表头部信息(为了防止在循环赋值中丢失前面的头部信息) 与 在循环相加连表示动态赋值的链表。
        ListNode* curr = nullptr; // 循环中动态赋值的链表
        ListNode* head = nullptr; // 存放链表头节点信息

        // 两个链表直接相加,得出来的数是不对的。因为讯在满十进位的问题。因此用 %10 得出本节点的数, 用 /10 得出进位数。 如果最后一个节点 对应相加 发现进位数。需要在链表尾部追加一个节点寻访进位数。
        int temp = 0; // 初始的进位数

        // 循环遍历需要相加的两个链表, 获取相应的值
        while (Nl1 != nullptr || Nl2 != nullptr)
        {
            // 取值 判断当前节点的值是否为空 如果为空 就给当前节点赋值(防止两个链表长度不一致,就给缺少的数赋值为0)
            int num1 = Nl1 ? Nl1->val : 0;
            int num2 = Nl2 ? Nl2->val : 0;

            int sum = num1 + num2 + temp; //对应节点值相加以及加上上一次计算的进位数
            temp = sum / 10; // 本次计算的进位数
            int val0 = sum % 10; //  本次计算的节点值

             // 给链表赋值。 并判断链表头部是否为空
             // 第一次存放时候 就是
            if (curr == nullptr)
            {
                // 先给curr链表赋值 进行动态更行
                curr = new ListNode(val0);
                // 把链表头节点值 存放在 head 链表中,后续curr指向next节点重置节点信息时,head不会被重置
                head = curr;
            }
            else
            {
                // 头部不为空 指定 next 节点 
                curr->next = new ListNode(val0);
                // curr链表向后移, 为下一次循环继续给next节点赋值
                curr = curr->next;
            }

            // l1 和 l2 链表向后移 获取下一个节点信息
            if (Nl1 != nullptr)
            {
                Nl1 = Nl1->next;
            }
            if (Nl2 != nullptr)
            {
                Nl2 = Nl2->next;
            }
        }
        // 判断最后一位进位数
        if (temp > 0)
            curr->next = new ListNode(temp);
        return head;
    }
};

结果如下:
在这里插入图片描述

三、扩展

代码如下(Visual Studio):自己输入两个目标数据集,然后返回数据集中元素个数,最后在进行累和。

#include <iostream>
using namespace std;


 struct ListNode {
     int val;          // 当前节点的数据
     ListNode *next;   // 下一个节点的地址
     ListNode() : val(0), next(nullptr) {}    // 设置当前节点的值为 0,下一个节点的地址为空。
     ListNode(int x) : val(x), next(nullptr) {}   // 将x的值赋给当前节点,下一个节点地址为空。
     ListNode(int x, ListNode *next) : val(x), next(next) {} // // 将x的值赋给当前节点,下一个节点地址为next。
 };

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* Nl1, ListNode* Nl2)
    {
        // 首先定义两个链表,分别存放 链表头部信息(为了防止在循环赋值中丢失前面的头部信息) 与 在循环相加连表示动态赋值的链表。
        ListNode* curr = nullptr; // 循环中动态赋值的链表
        ListNode* head = nullptr; // 存放链表头节点信息

        // 两个链表直接相加,得出来的数是不对的。因为讯在满十进位的问题。因此用 %10 得出本节点的数, 用 /10 得出进位数。 如果最后一个节点 对应相加 发现进位数。需要在链表尾部追加一个节点寻访进位数。
        int temp = 0; // 初始的进位数

        // 循环遍历需要相加的两个链表, 获取相应的值
        while (Nl1 != nullptr || Nl2 != nullptr)
        {
            // 取值 判断当前节点的值是否为空 如果为空 就给当前节点赋值(防止两个链表长度不一致,就给缺少的数赋值为0)
            int num1 = Nl1 ? Nl1->val : 0;
            int num2 = Nl2 ? Nl2->val : 0;

            int sum = num1 + num2 + temp; //对应节点值相加以及加上上一次计算的进位数
            temp = sum / 10; // 本次计算的进位数
            int val0 = sum % 10; //  本次计算的节点值

             // 给链表赋值。 并判断链表头部是否为空
             // 第一次存放时候 就是
            if (curr == nullptr)
            {
                // 先给curr链表赋值 进行动态更行
                curr = new ListNode(val0);
                // 把链表头节点值 存放在 head 链表中,后续curr指向next节点重置节点信息时,head不会被重置
                head = curr;
            }
            else
            {
                // 头部不为空 指定 next 节点 
                curr->next = new ListNode(val0);
                // curr链表向后移, 为下一次循环继续给next节点赋值
                curr = curr->next;
            }

            // l1 和 l2 链表向后移 获取下一个节点信息
            if (Nl1 != nullptr)
            {
                Nl1 = Nl1->next;
            }
            if (Nl2 != nullptr)
            {
                Nl2 = Nl2->next;
            }
        }
        // 判断最后一位进位数
        if (temp > 0)
            curr->next = new ListNode(temp);
        return head;
    }
};

// 对链表 l1 和 l2 进行赋值
ListNode* getvalue(ListNode* Lval)
{
    ListNode* curr0 = nullptr;
    int c;
    char d;
    while (cin >> c)
    {
        if (Lval == nullptr)
        {
            Lval = new ListNode(c);
            curr0 = Lval;
        }
        else
        {
            Lval->next = new ListNode(c);
            Lval = Lval->next;
        }
        if ((d = getchar()) == '\n')
            break;
    }
    return curr0;
}

// 获取链表长度
int getlength(ListNode* L)
{
    ListNode* t = nullptr;
    t = L->next;
    int sum = 0;
    while (t)
    {
        sum++;
        t = t->next;
    }
    cout << "链表的长度为(即链表节点个数为):" << sum+1 << endl;
    return sum;
}

// 输出累和的链表
void printList(ListNode* head)
{
    ListNode* phead = head;
    cout <<"类和结果为:" << "[";
    while (phead != NULL)
    {
        cout << phead->val << " ";
        phead = phead->next;
    }
    cout << "]" << "\n";
}

int main()
{
    Solution sol;
    ListNode* ans;

    ListNode* l1 = nullptr;
    ListNode* l2 = nullptr;
    cout << "请输入l1链表的值:" << endl;
    l1 = getvalue(l1);
    getlength(l1);
    cout << "请输入l2链表的值:" << endl;
    l2 = getvalue(l2);
    getlength(l2);

    ans = sol.addTwoNumbers(l1, l2);
    printList(ans);
    system("pause");
    return 0;
}

结果如下图所示:
示例一:
在这里插入图片描述
示例二:
在这里插入图片描述


  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浅尝写博客的爽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值