秒懂【链表相加】!超清晰图解一步步拆解。链表相加有的时候也叫两数相加

1.思路

对于给定的两个链表相加,首先是最后两个节点值的相加,接下来是倒数第二节点值的相加,从后向前执行节点值的相加。即:节点7与节点3相加,再执行节点3与节点6相加(还需加上进位数),最后是节点9与进位数的相加。

alt

也就是说链表的遍历是从后向前的,因此需要先对链表进行反转,再进行节点值的相加操作,最后再对新生成的链表反转。

具体步骤如下:

第一步:反转链表。

对两个链表指向反转操作(如果对链表反转不太熟悉,可以参考前面的文章:《可视化图解算法:反转链表》)。

alt

第二步:执行链表节点值相加操作。

在此过程中需要先定义一个虚拟头节点与进位的变量。

alt

节点3与节点6相加,注意进位值carry=1:

alt

h2指向为Null,新链表的节点为:h1指向的值+carry(进位值):

alt

当h2与h1都指向Null时,需要判断进位值carry是否为0,如果不为0,需要将carry的值单独形成一个节点:

alt

第三步:对新生成的链表反转。

alt

反转之后的链表如下所示:

alt

如果文字描述的不太清楚,你可以参考视频的详细讲解:B站@好易学数据结构

2.代码

2.1 Python代码

# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param head1 ListNode类
# @param head2 ListNode类
# @return ListNode类
#
class Solution:
    def addInList(self, head1: ListNode, head2: ListNode) -> ListNode:
        # write code here
        # 0. 当前链表为空,返回另外一个链表
        if head1 is None:
            return head2
        if head2 is None:
            return head1

        # 1. 翻转链表
        h1 = self.reverse(head1)
        h2 = self.reverse(head2)

        # 2. 执行链表节点值相加操作
        tmp_head = ListNode(-1)  # 虚拟临时头节点
        cur = tmp_head  # 衔接两个链表节点值相加形成的链表
        carry = 0  # 进位数
        # 2.1 相加链表节点的值
        while h1 is not None or h2 is not None:
            node_sum = 0
            # 当节点不为空的时候,则需要加上当前节点的值
            if h1 is not None:  # h1指针变量指向的值
                node_sum += h1.val
                h1 = h1.next
            if h2 is not None:
                node_sum += h2.val
                h2 = h2.next
            node_sum += carry  # 上一次计算的进位数
            val = node_sum % 10  # 本次相加结果的值
            carry = node_sum // 10  # 本次相加结果的进位数
            cur.next = ListNode(val)  # 衔接新链表节点
            cur = cur.next
        # 2.2 进位数操作(最后当两条链表都加完的时候,进位不为0的时,进位数需单独形成一个链表节点)
        if carry > 0:
            cur.next = ListNode(carry)
        # 3.翻转节点值相加形成的链表
        new_node = self.reverse(tmp_head.next)
        return new_node

    def reverse(self, head):
        pre = None  # (操作的)前序节点
        cur = head  # (操作的)当前节点
        nxt = head  # (操作的)下一个节点
        while cur:
            nxt = cur.next
            cur.next = pre
            pre = cur
            cur = nxt
        return pre

2.2 Java代码

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param head1 ListNode类
     * @param head2 ListNode类
     * @return ListNode类
     */
    public ListNode addInList (ListNode head1, ListNode head2) {
        // write code here
        // 0. 当前链表为空,返回另外一个链表
        if (head1 == null) {
            return head2;
        }
        if (head2 == null) {
            return head1;
        }

        // 1. 翻转链表
        ListNode h1 = reverse(head1);
        ListNode h2 = reverse(head2);

        // 2. 执行链表节点值相加操作
        ListNode tmpHead = new ListNode(-1); // 虚拟临时头节点
        ListNode cur = tmpHead;  //衔接两个链表节点值相加形成的链表
        int carry = 0; //进位数
        // 2.1 相加链表节点的值
        while (h1 != null || h2 != null) {
            int sum = 0;
            // 当节点不为空的时候,则需要加上当前节点的值
            if (h1 != null) {  //
                sum += h1.val;
                h1 = h1.next;
            }
            if (h2 != null) {  //h2指针变量指向的值
                sum += h2.val;
                h2 = h2.next;
            }
            sum += carry;  //上一次计算的进位数
            int val = sum % 10; // 本次相加结果的值
            carry = sum / 10; // 本次相加结果的进位数

            cur.next = new ListNode(val);
            cur = cur.next;
        }
        // 2.2 进位数操作(最后当两条链表都加完的时候,进位不为0的时,进位数需单独形成一个链表节点)
        if (carry > 0) {
            cur.next = new ListNode(carry);
        }
        // 3. 翻转节点值相加形成的链表
        ListNode newNode = reverse(tmpHead.next);
        return newNode;
    }

    private ListNode reverse(ListNode head) {
        ListNode pre = null;  // (操作的)前序节点
        ListNode cur = head; //(操作的)当前节点
        ListNode nxt = head; //(操作的)下一个节点
        while (cur != null) {
            nxt = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nxt;
        }
        return pre;
    }
}




2.3 Go代码


package main

import . "nc_tools"
/*
 * type ListNode struct{
 *   Val int
 *   Next *ListNode
 * }
 */

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param head1 ListNode类 
 * @param head2 ListNode类 
 * @return ListNode类
*/
func addInList( head1 *ListNode ,  head2 *ListNode ) *ListNode {
    // write code here
    // 0. 当前链表为空,返回另外一个链表
	if head1 == nil {
		return head2
	}
	if head2 == nil {
		return head1
	}

	// 1. 翻转链表
	h1 := reverse(head1)
	h2 := reverse(head2)

	// 2. 执行链表节点值相加操作
	tmpHead := &ListNode{Val: -1} // 虚拟临时头节点
	cur := tmpHead                //衔接两个链表节点值相加形成的链表
	carry := 0                    //进位数
	// 2.1 相加链表节点的值
	for h1 != nil || h2 != nil {
		sum := 0
		// 当节点不为空的时候,则需要加上当前节点的值
		if h1 != nil { //h1指针变量指向的值
			sum += h1.Val
			h1 = h1.Next
		}
		if h2 != nil { //h2指针变量指向的值
			sum += h2.Val
			h2 = h2.Next
		}
		sum += carry //上一次计算的进位数
		// 本次相加结果的值
		val := sum % 10
		// 本次相加结果的进位数(更新进位)
		carry = sum / 10
		// 衔接新链表节点
		cur.Next = &ListNode{Val: val}
		cur = cur.Next
	}
	// 2.2 进位数操作(最后当两条链表都加完的时候,进位不为0的时,进位数需单独形成一个链表节点)
	if carry > 0 {
		cur.Next = &ListNode{Val: carry}
	}
	// 3. 翻转节点值相加形成的链表
	newHead := reverse(tmpHead.Next)
	return newHead
}

func reverse(head *ListNode) *ListNode {
	var pre *ListNode //(操作的)前序节点
	cur := head       //(操作的)当前节点
	nxt := head       //(操作的)下一个节点
	for cur != nil {
		nxt = cur.Next
		cur.Next = pre
		pre = cur
		cur = nxt
	}
	return pre

}


如果上面的代码理解的不是很清楚,你可以参考视频的详细讲解:B站@好易学数据结构