Excaliburer`s Zone

It was challenging, but not risky.

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一.题目链接:https://leetcode.com/problems/add-two-numbers

二.题目大意:

  给定两个链表,每个链表表示一个非负数,不过数字的顺序是反过来存储的,要求给出这两个非负数的和,也是用一个链表以反顺序的形式来表示。

三.题解

  该题目有以下思路:

1.两个链表都反转过来,然后遍历,用两个vector把遍历的数值存起来,之后两个vector数值对应相加(此处的相加一开始是想的是转换成int型或long型,然后数值相加;不过仔细想了想这不就是大数加法么)最后的结果反转过来再存入新链表。这种方法实现比较复杂,空间复杂度O(n),时间复杂度O(m+n),不建议用此法。

2.仔细分析下这道题目,这些数字按从左向右的顺序实际上可以看成个位、十位。。。的顺序,所以可以直接按大数加法的思想,从左向右顺序相加;结合归并排序的思想,可以直接把结果放到已知的一个链表之中,就不用额外新建链表了,代码如下:

struct ListNode {
      int val;
      ListNode *next;
      ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            ListNode *p1 = l1;
            ListNode *p2 = l2;
            ListNode *p = p1;//最后的结果存在l1中
            ListNode *q1 = new ListNode(0);//表示l1中的最后一个节点
            ListNode *q2 = new ListNode(0);//表示l2中的最后一个节点
            int temp = 0;//表示进位
            while(p1&&p2)
            {   //记录最后一个节点的位置
                if(p1->next == NULL)
                    q1 = p1;
                if(p2->next == NULL)
                    q2 = p2;
                int _val = (p1->val + p2->val + temp) % 10;
                temp = (p1->val + p2->val + temp) / 10;
                p->val = _val;
                p1 = p1->next;
                p2 = p2->next;
                p = p->next;
            }
            if(p1&&!p2)//p1长度大于p2的长度
            {
            while(p1)
            {
                if(p1->next == NULL)
                    q1 = p1;
                int _val = (p1->val + temp) % 10;
                temp = (p1->val+temp) / 10;
                p->val = _val;
                p1 = p1->next;
                p = p->next;
            }
            //如果算完最后一个数的时候进位不为0,则链表增加一位
            if(temp != 0)
            {
                ListNode *q = new ListNode(1);
                q1->next = q;
            }
            return l1;
            }
            if(p2&&!p1){//p2的长度大于p1的长度
            q1->next = p2;
            p = p2;
            while(p2)
            {
                if(p2->next == NULL)
                    q2 = p2;
                int _val = (p2->val + temp) % 10;
                temp = (p2->val+temp) / 10;
                p->val = _val;
                p2 = p2->next;
                p = p->next;

            }
            if(temp != 0)
            {
                ListNode *q = new ListNode(1);
                q2->next = q;
            }
            return l1;
            }
            if(!p1&&!p2)//p1与p2的长度相同
            {
                if(temp != 0)
            {
                ListNode *q = new ListNode(1);
                q1->next = q;
            }
                return l1;
            }



    }
};

  该算法的时间复杂度为O(m+n),空间复杂度为O(1),但有几个需要注意的点:

1.两个链表相加时候,最后一位数计算完之后,如果进位不为0的话,就需要多增加一位,即链表多增加一个节点。

2.需要用额外的节点来记录已知链表的最后一个节点,便于后续的操作。

3.最后的计算结果存在l1中,如果l1的长度小于l2的话,还需将l1的末尾连接到l2的剩余部分(此处就会用到2中的额外节点了)。

4.关于大数加法的一个想法(与本题目关联不大):两个大数求和时,如果长度不一致的话,可通过高位补0使得两个大数的位数相同,然后求和会更加方便。

posted on 2017-11-12 16:50  Excaliburer  阅读(234)  评论(0编辑  收藏  举报