445. 两数相加 II 两种解法(数组和栈)

题目

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

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

进阶:

如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

示例:

输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 8 -> 0 -> 7

 解析

该题目有一个困惑点,就是结果要不要重用输入链表,重用的话有一个结果链表处理进位的问题,不重用的话直接创建节点会减少很多工作量,缺点就是空间占用会较多。

最容易想的方法就是翻转加完再翻转。不允许翻转的话,就是借助空间了,可以用一个辅助数组,长度的较长链表的长度,在链表上处理进位,再输出结果。第三种就是借助题目设定的反向处理——压栈,先入后出。

解法1:利于数组,重用输入链表,时间空间都很有效

class Solution {
    int cntNodes(ListNode* list) {
        if (NULL == list)
            return 0;
        
        int len = 0;
        while (list) {
            ++len;
            list = list->next;
        }

        return len;
    }
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        if (NULL == l1)
            return l2;
        if (NULL == l2)
            return l1;
        
        //l1指向长链表
        int len1 = cntNodes(l1);
        int len2 = cntNodes(l2);
        if (len1 < len2) {
            swap(l1, l2);
            swap(len1, len2);
        }

        //tmp存两个数的和
        vector<int> tmp(len1);
        ListNode *p = l1;
        for (int i = 0; i < len1; ++i) {
            tmp[i] = p->val;
            p = p->next;
        }
        p = l2;
        for (int i = len1-len2; i < len1; ++i) {
            tmp[i] += p->val;
            p = p->next;
        }

        //处理进位
        int chg = 0;
        for (int i = len1-1; i >= 0; --i) {
            tmp[i] = tmp[i]+chg;
            chg = tmp[i]/10;
            tmp[i] = tmp[i]%10;
        }

        //将数存入长链表
        p = l1;
        for (int i = 0; i < len1; ++i) {
            p->val = tmp[i];
            p = p->next;
        }
        if (chg) {
            ListNode* node = new ListNode(chg);
            node->next = l1;
            return node;
        }

        return l1;
    }
};

空间是O(max(m,n)),时间O(m+n)

解法2:利用栈,不重用输入链表

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        if (NULL == l1)
            return l2;
        if (NULL == l2)
            return l1;

        //链表入栈
        stack<int> sta1;
        stack<int> sta2;
        ListNode *p = l1;
        while (p) {
            sta1.push(p->val);
            p = p->next;
        }
        p = l2;
        while (p) {
            sta2.push(p->val);
            p = p->next;
        }

        //节点出栈
        ListNode dummy(0);
        ListNode *node = &dummy;
        int chg = 0;
        while (!sta1.empty() || !sta2.empty()) {
            int num = 0;
            if (!sta1.empty()) {
                num = sta1.top();
                sta1.pop();
            }
            if (!sta2.empty()) {
                num += sta2.top();
                sta2.pop();
            }

            num += chg;
            chg = num/10;
            num %= 10;

            p = new ListNode(num);
            p->next = node->next;
            node->next = p;
        }
        if (chg) {
            p = new ListNode(chg);
            p->next = node->next;
            node->next = p;
        }

        return dummy.next;
    }
};

    题解说用栈时间复杂度是O(max(m,n))(为啥我觉得是O(m+n)呢,压栈也算是遍历啊,不是压了两个栈么。。。),空间是O(m+n)。重用输入链表会带来很多的工作量。具体看自己怎么实现。

猜你喜欢

转载自blog.csdn.net/sy_123a/article/details/109320279