【数据结构与算法】之深入解析运用链表结构计算“两数相加”的算法实现

举报
Serendipity·y 发表于 2022/02/16 23:30:53 2022/02/16
【摘要】 一、题目要求 给出两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储 一位数字。请将两个数相加,并以相同形式返回一个表示和的链表(可以假设除了数字 0 之外,...

一、题目要求

  • 给出两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储 一位数字。请将两个数相加,并以相同形式返回一个表示和的链表(可以假设除了数字 0 之外,这两个数都不会以 0 开头)。
  • 示例 ①:

在这里插入图片描述

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807

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

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

  
 
  • 1
  • 2
  • 提示:
    • 每个链表中的节点数在范围 [1, 100] 内;
    • 0 <= Node.val <= 9;
    • 数据保证列表表示的数字不含前导零。

二、问题分析

  • 两数相加这道题,处理的就是最简单的数学加法运算,只是它是建立在链表的基础之上,所以难度在于对链表的处理。
  • 加法运算,除了每一位的加法之外,还需要考虑进位的情况。针对这道题来说,链表的每一个结点存储一位数字,并且是基于自然数字逆序存储,也就是链头到链尾保持个位到高位的顺序,这样就等于,进位的方向和单链表的方向一致。
  • 由于单链表的特性,没有前驱结点,无法回头。在这道题的场景下,就只需要一次 while 循环,从链头(低位)一直处理到链尾(高尾),就可以解决。但是需要注意处理进位的情况,每一位结点在计算之后,需要按 10 取余数,进行存储,多的需要进位到下一结点参与运算,正好这也符合单链表的处理思路。
  • 那么就需要几个变量,一个 carry 用来记录每一位运算后的进位,还需要一个 dummy 结点,用于记录两个链表加法运算后的链表结点。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 当处理到最长链表最后一个结点时,还需要对 carry(进位) 进行额外的处理,如果 carry 不为 0,表示继续向高位进位,需要额外在创建一个新的结点存储进位。

在这里插入图片描述

三、算法示例

  • Java 的算法示例:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
  // 计算结果存储的 dummy 结点
  ListNode dummy = new ListNode(0);
  ListNode p = l1, q = l2, curr = dummy;
  // 进位默认为 0
  int carry = 0;
  // 进入循环,以p和q两个链表指针都走到头为结束
  while (p != null || q != null) {
    int x = (p != null) ? p.val : 0;
    int y = (q != null) ? q.val : 0;
    // 进位参与运算
    int sum = carry + x + y;
    // 计算进位
    carry = sum / 10;
    // 构造新的结点存储计算后的位数数值
    curr.next = new ListNode(sum % 10);
    curr = curr.next;
    if (p != null)
      p = p.next;
    if (q != null)
      q = q.next;
  }
  // 处理数字最高位末尾进位情况
  if (carry > 0) {
    curr.next = new ListNode(carry);
  }
  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
  • 这里用 p 和 q 分别存储了 l1 和 l2 两个链表的结点,以此为循环依据。循环跳出的条件为两个链表都走到了末尾。
  • 每一次循环中,处理每一位结点数数值并加上进位 carry 的值,运算后将数值取余存入新的结点,并将新的进位数存入 carry 进行存储。
  • 最后需要注意,当两个链表都处理完成之后,还需要判断最高位是否需要进位(carry > 0)。如果需要,创建一个新的链表结点存储进位值。
  • C++ 的算法示例:
class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            ListNode *head = nullptr, *tail = nullptr;
            int carry = 0;
            while (l1 || l2) {
                int n1 = l1 ? l1->val: 0;
                int n2 = l2 ? l2->val: 0;
                int sum = n1 + n2 + carry;
                if (!head) {
                    head = tail = new ListNode(sum % 10);
                } else {
                    tail->next = new ListNode(sum % 10);
                    tail = tail->next;
                }
                carry = sum / 10;
                if (l1) {
                    l1 = l1->next;
                }
                if (l2) {
                    l2 = l2->next;
                }
            }
            if (carry > 0) {
                tail->next = new ListNode(carry);
            }
            return head;
        }
};

  
 
  • 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

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

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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