算法题学习---链表相加(二)

102 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情

题目

描述

假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。

给定两个这种链表,请生成代表两个整数相加值的结果链表。

数据范围:0≤n,m≤1000000,链表任意值 0≤val≤9 要求:空间复杂度 O(n),时间复杂度 O(n)

例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

示例1

输入:
[9,3,7],[6,3]
返回值:
{1,0,0,0}
说明:
如题面解释     

示例2

输入:
[0],[6,3]
返回值:
{6,3}

备注:

1≤n,m≤106 0≤ai,bi≤9

分析

考虑特殊情况

在进行问题分析过程前,我们先考虑一下特殊情况,那么在这道问题中,有哪些情况是特殊的呢?

不难发现,如下情况:

  • head1为空指针,说明是0加另一个数,此时只需要返回另一个头结点就行(head2为空指针也是相同的情况);

考虑一般情况

  • 链表反转

首先我们可以看到题目中描述的链表中的数据是从高位到低位的,但是我们正常的加法运算都是从低往高位进行计算的,所以我们可以考虑先将链表进行反转,然后再做处理。

  • 加法运算

在我们做加法运算时,可以考虑以哪一个链表作为主链表,基于这样一个原因,两个n位数相加,最多会生成一个n+1位数,所以我们可以将较长的链表作为主链表,并增加一个pReturn节点。

使用两个指针同时访问这两个链表,然后做加法,并进行进位操作,依次操作,最后如果进位还有标志,那就需要增加一个节点保存多余的一位信息。

由于我们使用了较长的链表作为返回信息的主要组成部分,所以在空间上面复杂度可以达到O(1)

  • 返回信息

前面的计算信息是链表逆序的,这里我们还需要将结果链表再反过来。

如果pReturn节点的值为0,那就返回pReturn->next;

如果pReturn节点的值为1,那就返回pReturn.

题解中参考的处理步骤:

  • step 1:任意一个链表为空,返回另一个链表就行了,因为链表为空相当于0,0加任何数为0,包括另一个加数为0的情况。
  • step 2:相继反转两个待相加的链表,反转过程可以参考反转链表。
  • step 3:设置返回链表的链表头,设置进位carry=0.
  • step 4:从头开始遍历两个链表,直到两个链表节点都为空且carry也不为1. 每次取出不为空的链表节点值,为空就设置为0,将两个数字与carry相加,然后查看是否进位,将进位后的结果(对10取模)加入新的链表节点,连接在返回链表后面,并继续往后遍历。

注意:这里增加了新的节点,所以空间复杂度是O(n)的。

  • step 5:返回前将结果链表再反转回来。

代码示例

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */

class Solution {
  public:
    /**
     *
     * @param head1 ListNode类
     * @param head2 ListNode类
     * @return ListNode类
     */
    ListNode* addInList(ListNode* head1, ListNode* head2) {
        // write code here
        if (nullptr == head1) {
            return head2;
        }
        if (nullptr == head2) {
            return head1;
        }

        // the head point
        ListNode* pReturn = new ListNode(0);
        ListNode* pQuick = nullptr;
        ListNode* pSlow = nullptr;
        ListNode* pLong = nullptr;

        // reverse list
        int length1 = GetLinkListLength(head1);
        int length2 = GetLinkListLength(head2);
        ListNode* pReverse1 = ReverseLinkList(head1);
        ListNode* pReverse2 = ReverseLinkList(head2);
        pQuick = pReverse1;
        pLong = pReverse1;
        pSlow = pReverse2;
        if (length2 > length1) {
            pLong = pReverse2;
            pQuick = pReverse2;
            pSlow = pReverse1;
        }

        int entry = 0;
        ListNode* pPre = nullptr;
        while (nullptr != pSlow || nullptr != pQuick) {
            int SlowVal = nullptr == pSlow ? 0 : pSlow->val;

            pQuick->val += SlowVal + entry;
            entry = pQuick->val/10;
            pQuick->val %= 10;

            pPre = pQuick;
            pQuick = pQuick->next;
            pSlow = nullptr == pSlow ? nullptr : pSlow->next;
        }
        pPre->next = pReturn;
        pReturn->val = entry;

        pReturn = ReverseLinkList(pLong);
        if (pReturn->val == 1) {
            return pReturn;
        } else {
            return pReturn->next;
        }
    }

    int GetLinkListLength(ListNode* head) {
        int length = 0;
        while (nullptr != head) {
            length++;
            head = head->next;
        }
        return length;
    }

    ListNode* ReverseLinkList(ListNode* head) {
        if (nullptr == head || nullptr == head->next) {
            return head;
        }

        ListNode* pPre = nullptr;
        ListNode* pCur = head;
        ListNode* pNext = head->next;

        while (nullptr != pCur) {
            pNext = pCur->next;
            pCur->next = pPre;
            pPre = pCur;
            pCur = pNext;
        }
        return pPre;
    }
};