Leetcode2.两数相加 - 两种方式

本文介绍如何解决LeetCode两数相加问题,通过链表存储逆序整数并进行加法运算,提供两种解决方案及其实现代码,讨论了内存泄露和链表断开等问题。

两数相加导图

食用指南:

Leetcode专栏开启了,由于博主闭关期末,所以每日只能一题
尽量做到一题多解,先说思路,之后代码实现,会添加必要注释
语法或STL内容会在注意点中点出,新手友好
欢迎关注博主神机百炼专栏,内涵算法基础详细讲解和代码模板

题目描述:

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

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

    你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

  • 代码背景

/**
 * 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) {

    }
};
  • 题目来源:https://leetcode.cn/problems/add-two-numbers/

题目分析:

  • 问题隐患:

    最高位进位可能为1,可能为0,为0时不进位。

  • 法一:从头节点开始存储位,多余尾节点需要删除
    用头

  • 法二:从头节点下一节点存储位,return 头节点的下一节点
    空头

算法模板:

代码实现:

法一:删尾

  • 删除尾节点需要将尾节点的前一节点的next指向NULL,防止内存泄露
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode();
        auto p = head;
        ListNode* q = NULL;	//记录尾节点的上一节点
        int t = 0;
        while(l1 || l2){
            if (l1) t += l1->val, l1 = l1->next;
            if (l2) t += l2->val, l2 = l2->next;
            p->val = t %10;
            t /= 10;
            p->next = new ListNode();
            q = p;
            p = p->next;
        }
        if (t) p->val = t;
        else delete p, q->next = NULL;
        return head;
    }
};
错因1:内存泄露
  • 若最终不将删除节点的上一节点的next指针指向NULL,
    遍历链表时势必导致内存泄露
    报错如下:

    ==42==ERROR: AddressSanitizer: heap-use-after-free on address Ox6020000001b8 at pc Ox00000037afd4 bp 0x7fff22030230 sp 0x7fff22030228 READ of size 8 at Ox6020000001b8 thread TO
    内存泄露

法二:空头

  • 一定要保证节点和节点之间依靠next指针连接,

    不然导致链表断开,直接造成答案不全,甚至内存泄漏

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        auto head = new ListNode();
        auto p = head;
        int t = 0;
        while(l1 || l2 || t){
            if (l1) t += l1->val, l1 = l1->next;
            if (l2) t += l2->val, l2 = l2->next;
            p->next = new ListNode(t % 10);//注意此处用next连接下一节点
            t /= 10;
            p = p->next;
        }
        return head->next;
    }
};
错因2:链表断开
  • 来看看链表没连接上的错误情况:
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        auto head = new ListNode();
        auto p = head->next;	//此处链表尚且连接
        int t = 0;
        while(l1 || l2 || t){
            if (l1) t += l1->val, l1 = l1->next;
            if (l2) t += l2->val, l2 = l2->next;
            p = new ListNode(t % 10);	
            //此处p不再是next指向的空间,而是操作系统分配的ListNode空间
            //链表节点断开
            t /= 10;
            p = p->next;
        }
        return head->next;
    }
};

链表节点断开

注意点:

1. 删除链表节点后造成的内存泄露:

  • 我们学习delete关键字的时候,经常看见这句话:
    delete指针指向空间后,应该将指针指向NULL
int *p = &a;
delete p;
p = NULL;
  • 这句话本意是对的,但是对于链表删除尾节点,还需要加一句
    delete 链表尾节点指针p后
    将p指针和尾节点的上一节点的next指针都指向NULL

    防止遍历链表时内存泄露

  • 内存泄露体现在Leetcode上是:
    ==42==ERROR: AddressSanitizer

  • 体现在本地编译器上是:
    疯狂打印地址
    内存泄露

2. 构造链表未使用next导致节点不相连:

  • 现手动构造一个ListNode *l1
  • 先指向空间,再创建节点,导致链表不连接
ListNode* l1 = new ListNode(2);
ListNode* p = l1->next;	//p指向l1的next
p = new ListNode(4);	//p指向新创建的1号空间,不指向l1的next了
p = p->next;			//p指向1号空间的next
p = new ListNode(3);	//p指向新创建的2号空间,不指向一号空间的next了
  • 先创建节点,再指向空间,链表还是连接的
ListNode* l1 = new ListNode(2);
ListNode* p = new ListNode(4);
l1->next = p;
ListNode* q = new ListNode(3);
p->next = q;
  • 上述连接的代码还可以这样写:
ListNode *l1 = new ListNode(2);
ListNode *p = l1;	//p指向1号节点
p->next = new ListNode(4);
p = p->next;		//p指向2号节点
p ->next = new ListNode(3);
p = p->next;		//p指向3号节点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

starnight531

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

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

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

打赏作者

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

抵扣说明:

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

余额充值