leetcode:445. 两数相加 II

题目来源

445. 两数相加 II

题目描述

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


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

    }
};

题目解析

分析数据量

  • 很小,说明可以随便造
    在这里插入图片描述

不推荐的写法:

  • 将两个链表先算出各自代表的整数,然后求出两个整数的和,最后将这个和转换为链表的形式。
  • 为什么不推荐?因为链表的长度可以很长,因此可能会溢出。

难点在于:

  • 我们进行加法运算都是从低位到高位计算
  • 然后链表的最低位在链表末尾,链表只能从前往后遍历,没法取到前面的元素

怎么办呢?

使用栈

利用栈后入先出的特性逆序访问链表

  • 将两个链表分别从左到右遍历,遍历过程中将值压栈,这样就生成了两个链表节点的逆序栈,分别表示stackA、stackB
  • 将stackA和stackB同步弹出,这样就相当于两个链表从低位到高位依次弹出,在这个过程中生成相加链表即可,同时需要关注【每一位是否有进位】,用c 表示
  • 返回栈的头节点
#include <stack>
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    std::stack<int> stackA, stackB;

    ListNode *iter = l1;
    while (iter){
        stackA.push(iter->val);
        iter = iter->next;
    }

    iter = l2;
    while (iter){
        stackB.push(iter->val);
        iter = iter->next;
    }

    ListNode * dummy = new ListNode(-1), *newNode;
    int c = 0, y = 0;
    while (!stackA.empty() or !stackB.empty() or c > 0){
        int a = stackA.empty() ? 0 : stackA.top();
        int b = stackB.empty() ? 0 : stackB.top();
        if(!stackA.empty()){
            stackA.pop();
        }
        if(!stackB.empty()){
            stackB.pop();
        }
        y = (a + b + c) % 10;
        c = (a + b + c) / 10;
        newNode = new ListNode(y);
        newNode->next = dummy->next;
        dummy->next = newNode;
    }

    return dummy->next;
}

反转链表

利用链表的逆序,这样就可以省掉栈的空间。

  • 将两个链表逆序,这样就可以依次得到从低位到高位的数字
  • 同步遍历两个逆序后的链表,这样就依次得到两个链表从低位到高位的数字,在这个过程中生成相加链表即可,同时需要关注【进位】
  • 将逆序的链表再逆序一次,返回结果
class Solution {
    ListNode* reverseList(ListNode* node){
        if(node == nullptr || node->next == nullptr){
            return node;
        }
        
        ListNode *ret = reverseList(node->next);
        node->next->next = node;
        node->next = nullptr;
        return ret;
    }
    
    
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        l1 = reverseList(l1);
        l2 = reverseList(l2);
        
        ListNode *dummy = new ListNode(-1);
        ListNode *l = dummy;
        int c = 0;
        while (l1 != nullptr || l2 != nullptr || c != 0){
            int a = l1 != nullptr ? l1->val : 0;
            int b = l2 != nullptr ? l2->val : 0;
            l->next = new ListNode((a + b + c) % 10);
            c = (a + b + c) / 10;
            
            l1 = l1 != nullptr ? l1->next : nullptr;
            l2 = l2 != nullptr ? l2->next : nullptr;
            l = l->next;
        }
        
        auto ret = reverseList(dummy->next);
        delete dummy;
        return ret;
    }
};

优化:插入新链表时可以采用头插法,这样就不需要反转链表了

递归

为什么可以用递归?

  • 递归本质是栈,所以也可以从后往前取数字

测试

int main()
{
    ListNode* listA = new ListNode(-1), *moveA = listA;
    ListNode* listB = new ListNode(-1), *moveB = listB;

    std::vector<int> vectorA = {7, 2, 4, 3};
    for(auto i : vectorA){
        moveA->next = new ListNode(i);
        moveA = moveA->next;
    }

    vectorA = {5, 6, 4};
    for(auto i : vectorA){
        moveB->next = new ListNode(i);
        moveB = moveB->next;
    }

    addTwoNumbers(listA->next, listB->next);

    return 0;
}

类似题目

加法运算

乘法运算

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值