445. 两数相加 II

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

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

进阶:

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

示例:

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

解答:

思路1:

刚拿到这个题目的时候,第一反应就是和我们平时做加法一样,将每一位对其,然后对应位上的数字进行相加,生成一个新的链表。这应该也是这个题目想要考察的。但是现在面临一个问题就是两数相加应该是从各位开始加,但是对于单链表的访问只能从最高位进行访问,所以应该先将链表进行反转的操作。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    // 反转链表函数
    void reverse(ListNode* &list){
        vector<int> vec;
        ListNode* p = list;
        while(p != NULL){
            vec.push_back(p->val);
            p = p->next;
        }
        p = list;
        for(int i=vec.size()-1; i>=0; i--){
            p->val = vec[i];
            p = p->next;
        }
    }

    // 尾插函数(返回新插入的节点)
    ListNode* backInsert(ListNode* node, int num){
        ListNode* s = new ListNode(num);
        node->next = s;
        s->next = NULL;
        return s;
    }

    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        // 首先反转初始的两个链表
        reverse(l1);
        reverse(l2);

        ListNode* new_List = new ListNode(-1);
        ListNode* head = new_List;

        // 进行相加操作
        bool b = false;  // 标记是否大于等于10
        while(l1 != NULL && l2 != NULL){
            int num = 0;
            if(b == true){
                num = l1->val + l2->val + 1;
                b = false;
            }else
                num = l1->val + l2->val;
            if(num >=10){
                b = true;
                num = num - 10;
            }
            new_List = backInsert(new_List, num);
            l1 = l1->next;
            l2 = l2->next;
        }

        // 考虑到链表长度相等的情况(是否需要进位)
        if(l1 == NULL && l2 == NULL){
            if(b == true)
                new_List = backInsert(new_List, 1);
            reverse(head->next);
            return head->next;
        }

        // 对较长的链表进行添加(l1和l2只会执行一个)
        // 和前面的相同,只不过只有一个链表
        while(l1 != NULL){
            int num = 0;
            if(b == true){
                num = l1->val + 1;
                b = false;
            }else   
                num = l1->val;
            if(num >=10){
                b = true;
                num = num - 10;
            }
            new_List = backInsert(new_List, num);
            l1 = l1->next;
        }

        while(l2 != NULL){
            int num = 0;
            if(b == true){
                num = l2->val + 1;
                b = false;
            }else   
                num = l2->val;
            if(num >=10){
                b = true;
                num = num - 10;
            }
            new_List = backInsert(new_List, num);
            l2 = l2->next;
        }

        // 判断最后是否需要进位(需要进位)
        if(b == true){
            new_List = backInsert(new_List, 1);
        }

        // 反转相加后的链表
        reverse(head->next);
        // 返回结果
        return head->next;
    }
};

思路2:

除了这种方法,我还想到了另一种方法。就是先将两个链表中的数字转换为真实的数字,然后将真实的数字相加得到最终相加的数字,最后将这个结果存储到一个新的链表中去。但是这种方法的局限性就是:我们无法表示无穷大的数,根据数据类型只能存储有限大的数,不过我觉得也是一种思路,具体的实现代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    // 前插函数(返回新插入的节点)
    ListNode* frontInsert(ListNode* node, int num){
        ListNode* s = new ListNode(num);
        s->next = node;
        return s;
    }

    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    
        int len1 = 0;  // 计算第一个链表的长度
        ListNode* p1 = l1;
        while(p1 != NULL){
            p1 = p1->next;
            len1++;
        }

        long real_num1 = 0;
        p1 = l1;
        for(int i=len1-1; i>=0; i--){
            long num = p1->val;  // 取出相应节点中的数
            for(int j = 0; j < i; j++){  // 对每一位上的数字扩大相应的倍数
                num = num * 10;
            }
            real_num1 = real_num1 + num;  // 每一位数字相加
            p1 = p1->next;  // 节点移动
        }

        int len2 = 0;  // 计算第二个链表的长度
        ListNode* p2 = l2;
        while(p2 != NULL){
            p2 = p2->next;
            len2++;
        }

        long real_num2 = 0;
        p2 = l2;
        for(int i=len2-1; i>=0; i--){
            long num = p2->val;  // 取出相应节点中的数
            for(int j = 0; j < i; j++){  // 对每一位上的数字扩大相应的倍数
                num = num * 10;
            }
            real_num2 = real_num2 + num;  // 每一位数字相加
            p2 = p2->next;  // 节点移动
        }

        // 计算得到相加之后的真实数字
        long real_num = real_num1 + real_num2;

        // 将相加之后的真实数字转换为链表(注意需要向前插入)
        ListNode* new_node = NULL;
        // 判断相加后结果是否为0
        if(real_num == 0)
            new_node = new ListNode(0);
        else{
            while(real_num > 0){
            // 取出个位数字
            int num = 0;
            num = real_num % 10;
            real_num = real_num/10;
            // 调用前插函数         
            new_node = frontInsert(new_node, num);
            }
        }
        
        return new_node;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MYH永恒

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

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

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

打赏作者

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

抵扣说明:

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

余额充值