【数据结构与算法】之深入解析“两数相加II”的求解思路与算法示例

举报
Serendipity·y 发表于 2022/02/17 00:57:12 2022/02/17
【摘要】 一、题目要求 给你两个非空链表来代表两个非负整数,数字最高位位于链表开始位置,它们的每个节点只存储一位数字,将这两数相加会返回一个新的链表。可以假设除了数字 0 之外,这两个数字都不会以零开头。示例1:...

一、题目要求

  • 给你两个非空链表来代表两个非负整数,数字最高位位于链表开始位置,它们的每个节点只存储一位数字,将这两数相加会返回一个新的链表。
  • 可以假设除了数字 0 之外,这两个数字都不会以零开头。
  • 示例1:

在这里插入图片描述

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

  
 
  • 1
  • 2
  • 示例2:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]

  
 
  • 1
  • 2
  • 示例3:
输入:l1 = [0], l2 = [0]
输出:[0]

  
 
  • 1
  • 2
  • 提示:
    • 链表的长度范围为 [1, 100];
    • 0 <= node.val <= 9;
    • 输入数据保证链表代表的数字无前导 0。

二、求解算法

① 栈

  • 本题的主要难点在于链表中数位的顺序与我们做加法的顺序是相反的,为了逆序处理所有数位,可以使用栈:把所有数字压入栈中,再依次取出相加,计算过程中需要注意进位的情况。
  • C++ 示例:
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack<int> s1, s2;
        while (l1) {
            s1.push(l1 -> val);
            l1 = l1 -> next;
        }
        while (l2) {
            s2.push(l2 -> val);
            l2 = l2 -> next;
        }
        int carry = 0;
        ListNode* ans = nullptr;
        while (!s1.empty() or !s2.empty() or carry != 0) {
            int a = s1.empty() ? 0 : s1.top();
            int b = s2.empty() ? 0 : s2.top();
            if (!s1.empty()) s1.pop();
            if (!s2.empty()) s2.pop();
            int cur = a + b + carry;
            carry = cur / 10;
            cur %= 10;
            auto curnode = new ListNode(cur);
            curnode -> next = ans;
            ans = curnode;
        }
        return ans;
    }
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • Java 示例:
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer> stack1 = new LinkedList<Integer>();
        Deque<Integer> stack2 = new LinkedList<Integer>();
        while (l1 != null) {
            stack1.push(l1.val);
            l1 = l1.next;
        }
        while (l2 != null) {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        int carry = 0;
        ListNode ans = null;
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) {
            int a = stack1.isEmpty() ? 0 : stack1.pop();
            int b = stack2.isEmpty() ? 0 : stack2.pop();
            int cur = a + b + carry;
            carry = cur / 10;
            cur %= 10;
            ListNode curnode = new ListNode(cur);
            curnode.next = ans;
            ans = curnode;
        }
        return ans;
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

② 反转链表

  • 先把两个链表反转后再相加,因为从低位开始做加法比较直观,加法运算完成后再反转整个链表后返回。
  • 反转之后的链表的头节点表示个位数,尾节点表示最高位;从两个链表的头节点开始相加,就相当于从整数的个位数开始相加。
  • 要注意进位,如果两个整数的个位数相加的和超过 10,就会往十位数产生一个进位,在下一步做十位数相加时就要把这个进位考虑进去。
  • C++ 示例:
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        // 若任一链表为空,则直接返回另一链表
        if (l1 == nullptr || l2 == nullptr) return l1 == nullptr ? l2 : l1;
        l1 = reverseList(l1), l2 = reverseList(l2);     // 反转链表,便于进行加法运算
        return reverseList(addList(l1, l2));            // 相加后再反转,最后返回结果
    }

	// 反转链表模板
    ListNode* reverseList(ListNode* head) {
        if (head == nullptr) return head;

        ListNode *pre = head, *cur = head->next;
        while (cur) {
            ListNode *ne = cur->next;
            cur->next = pre;
            pre = cur, cur = ne;
        }
        head->next = nullptr;
        return pre;
    }

	// 链表相加
    ListNode* addList(ListNode* l1, ListNode* l2) {
        ListNode *dummy = new ListNode(0);
        ListNode *p = dummy;

        int carry = 0;     // 进位标志
        while (l1 || l2) {
            // 节点不为空就将当前的两个节点的值加起来,为空就加0
            carry += (l1 == nullptr ? 0 : l1->val) + (l2 == nullptr ? 0 : l2->val);
            
            // 如果当前节点有进位,就对10取模,没有进位就保持原值
            // p = p->next = xx 表示 p->next = xx, p = p->next两条语句的组合
            p = p->next = new ListNode(carry % 10);
            
            // 如果有进位,则carry余1, 没有进位则carry重置为0
            carry /= 10;

            if (l1) l1 = l1->next;
            if (l2) l2 = l2->next;
        }

        // 判断最高位是否有进位,有的话就再追加一个1即可
        if (carry) p->next = new ListNode(1);
        return dummy->next;
    }
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

文章来源: blog.csdn.net,作者:Serendipity·y,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/Forever_wj/article/details/122440299

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。