数据结构与算法之运用链表结构计算两数相加的算法实现

Posted Forever_wj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法之运用链表结构计算两数相加的算法实现相关的知识,希望对你有一定的参考价值。

一、题目要求

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

	输入:l1 = [2,4,3], l2 = [5,6,4]
	输出:[7,0,8]
	解释:342 + 465 = 807
  • 示例 ②:
	输入:l1 = [0], l2 = [0]
	输出:[0]
  • 示例 ③:
	输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
	输出:[8,9,9,9,0,0,0,1]
  • 提示:
    • 每个链表中的节点数在范围 [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;
	}
  • 这里用 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;
	    }
	};

以上是关于数据结构与算法之运用链表结构计算两数相加的算法实现的主要内容,如果未能解决你的问题,请参考以下文章

每天一道算法题(java数据结构与算法)——> 链表中的两数相加

数据结构与算法Leetcode2:两数相加链表学习

数据结构与算法 —— 链表linked list(02)

数据结构与算法全套数据结构笔记持续更新

数据结构与算法全套数据结构笔记持续更新

leetcode 算法题2 两数相加