力扣刷题攻略链表篇-链表高精度加法


文章内容是自己刷leetcode官方刷题攻略的一些经验与总结。
题目链接详见 leetcode刷题攻略
如果喜欢的话,别忘了点个赞哦 ^ _ ^

一. 2 两数相加

1.题目描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题目分析与解答

题目中给的两个链表就相当于是两个加数,而且是逆序存储,也就是说,链表从前往后遍历,就正好符合加数从低位往高位开始加的运算逻辑

我们同时遍历两个链表将相应位置的 value 相加即可,在这个过程中,我们需要记录一个进位位,初始化为 0。根据进位位的值以及两个 value 来确定当前位置的和是多少

两个链表长度可能不同,我们在遍历过程中,如果发现有一条链表遍历完了,那么可以假设该链表的当前节点的值是一个 0,直到两个链表都遍历结束。

最后如果进位位不为 0,我们需要在答案的最后增加一个节点

C++ 代码如下:

/**
 * 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) {
        //设置一个进位位
        //逆序存储相当于就是从低位开始相加,符合正常的运算逻辑
        //我们不用计算具体数字,只用找到相加后的链表即可
        //两个链表长度可能不同
        //注意最后处理进位

        int carry = 0;
        ListNode *head = nullptr, *tail = nullptr;
        while(l1 || l2) {
            int n1 = l1 ? l1->val : 0;
            int n2 = l2 ? l2->val : 0;
            int sum = n1 + n2 + carry;
            carry = sum / 10;
            if(head == nullptr) {
                head = tail = new ListNode(sum % 10, nullptr);
            } else {
                tail->next = new ListNode(sum % 10, nullptr);
                tail = tail->next;
            }

            if(l1) l1 = l1->next;
            if(l2) l2 = l2->next;
        }

        if(carry > 0) {
            tail->next = new ListNode(carry, nullptr);
        }

        return head;

    }
};

二. 445 两数相加II

1.题目描述

在这里插入图片描述
在这里插入图片描述

2.反转链表解法

这道题目与上道题目的区别是链表的起始位置为数字的高位,我们不能一边遍历一边运算(应该从低位开始算)。

这里有两种解题思路。

第一种是将原始链表进行翻转,然后步骤就和 2.两数相加 这道题一样了,注意要将最后得到的链表再次进行翻转才是答案需要的链表。

时间复杂度 O(max(m,n)), 空间复杂度 O(1)。

C++ 代码如下:

/**
 * 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) {
        //如果将链表进行翻转那么就和两数相加这道题一样了
        //注意最后输出进行翻转
        
        //反转链表
        l1 = Reverse(l1);
        l2 = Reverse(l2);

        //测试反转链表函数
        // ListNode *cur = l1;
        // while(cur) {
        //     cout << cur->val << " ";
        //     cur = cur->next;
        // }
        // cout << endl;
        // cur = l2;
        // while(cur) {
        //     cout << cur->val << " ";
        //     cur = cur->next;
        // }
        // cout << endl;

        //两数相加
        ListNode *head = nullptr, *tail = nullptr;
        int carry = 0;
        while(l1 || l2) {
            int n1 = l1 ? l1->val : 0;
            int n2 = l2 ? l2->val : 0;
            int sum = n1 + n2 + carry;
            carry = sum / 10;
            if(head == nullptr) {
                head = tail = new ListNode(sum % 10, nullptr);
            } else {
                tail->next = new ListNode(sum % 10, nullptr);
                tail = tail->next;
            }

            if(l1) l1 = l1->next;
            if(l2) l2 = l2->next;
        }

        //处理进位
        if(carry) {
            tail->next = new ListNode(1, nullptr);
        }

        //注意最后的输出也要翻转回来
        return Reverse(head);


    }

    ListNode* Reverse(ListNode *head) {
        ListNode *cur = head;
        ListNode *pre = nullptr;
        while(cur) {
            ListNode *tem = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tem;
        }
        return pre;
    }
};

3.使用栈求解

第二种解法是使用栈这种数据结构,利用它先进后出的性质

我们将两个链表的数值放到两个栈中,在遍历两个栈,那么此时栈顶元素就是对应加数的低位,后面的过程就和两数相加这道题目类似了。

时间复杂度 O(max(m,n)), 空间复杂度 O(m+n)。

C++ 代码如下:

/**
 * 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) {
        //如果将链表进行翻转那么就和两数相加这道题一样了
        //注意最后输出进行翻转
        //时间复杂度O(max(m,n)) 空间复杂度O(1)
        
        //如果不翻转链表的话,可以用栈(不能叫优化),正好满足先进后出的运算顺序
        //时间复杂度O(max(m,n)) 空间复杂度O(m+n)

        stack<int> s1, s2;
        //入栈
        while(l1) {
            s1.push(l1->val);
            l1 = l1->next;
        }
        while(l2) {
            s2.push(l2->val);
            l2 = l2->next;
        }
        
        int carry = 0;
        ListNode *head = nullptr;
        while(!s1.empty() || !s2.empty() || carry) {
            int n1 = s1.empty() ? 0 : s1.top();
            int n2 = s2.empty() ? 0 : s2.top();
            if(!s1.empty()) s1.pop();
            if(!s2.empty()) s2.pop();
            int sum = n1 + n2 + carry;
            carry = sum / 10;
            ListNode * tem = new ListNode(sum % 10, head);
            head = tem;
        }

        return head;

    }

    
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Echo夏末

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

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

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

打赏作者

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

抵扣说明:

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

余额充值