链表加一问题中的「虚拟头节点」魔法

链表加一问题中的「虚拟头节点」魔法

今天我们来拆解 LeetCode 369 题「给单链表加一」,重点分析代码中巧妙使用的 虚拟头节点(dummy node) 设计模式。这一设计在链表问题中非常常见,掌握它能让你在处理边界条件时游刃有余。

问题描述

给定一个单链表表示的非负整数(最高位在链表头),将该整数加一。例如:

  • 输入 [1,2,3] → 输出 [1,2,4]
  • 输入 [9,9,9] → 输出 [1,0,0,0]

核心思路分析

加一操作的关键在于处理进位:

  1. 找到最后一个非9的节点:从右到左遍历链表,找到最后一个不是9的节点(因为它加一后不会产生连续进位)。
  2. 处理进位:将该节点加一,后续所有节点置0。
  3. 处理最高位进位:如果原链表所有节点都是9(如 [9,9,9]),加一后需要在链表最前面新增一个1。

为什么需要虚拟头节点?

当链表所有节点都是9时,加一后需要创建新的头节点。此时,虚拟头节点可以:

  • 统一处理头节点变化的情况(无需额外判断是否需要新增节点)。
  • 简化代码逻辑,避免边界条件的冗余判断。

代码逐行解析

public class Solution {
    public ListNode PlusOne(ListNode head) {
        if (head == null) return new ListNode(1); // 空链表特殊处理

        ListNode dummy = new ListNode(0); // 创建虚拟头节点
        dummy.next = head; // 虚拟头节点指向原链表头
        ListNode notNine = dummy; // 记录最后一个非9节点

        // 第一步:找到最后一个非9节点
        ListNode current = head;
        while (current != null) {
            if (current.val != 9) {
                notNine = current; // 更新最后一个非9节点
            }
            current = current.next;
        }

        // 第二步:最后一个非9节点加一
        notNine.val++;
        notNine = notNine.next; // 移动到后续节点

        // 第三步:后续节点全部置0
        while (notNine != null) {
            notNine.val = 0;
            notNine = notNine.next;
        }

        // 返回结果:如果虚拟头节点的值为0,说明未修改原头节点,否则返回虚拟头节点
        return dummy.val == 0 ? head : dummy;
    }
}

虚拟头节点的作用演示

假设原链表为 [9,9,9]

  1. 初始化dummy.next 指向原头节点 9
  2. 寻找最后一个非9节点:遍历后发现所有节点都是9,因此 notNine 仍为 dummy(初始值为0)。
  3. 加一操作dummy.val++ → dummy 变为1。
  4. 后续节点置0:原链表所有节点变为0。
  5. 返回结果dummy.val != 0,返回 dummy,最终链表为 [1,0,0,0]

为什么不用虚拟头节点会更复杂?

如果不使用虚拟头节点,处理最高位进位时需要:

  1. 检查头节点是否为9。
  2. 如果所有节点都是9,创建新节点并返回。
  3. 否则返回原头节点。

这会导致代码中出现冗余的分支判断。而虚拟头节点将所有情况统一处理,代码更简洁。

总结

虚拟头节点的核心价值在于:

  • 统一处理头节点变化:无论是新增节点还是修改原头节点,都通过同一逻辑处理。
  • 简化边界条件:避免在代码中频繁判断头节点是否为空或是否需要修改。

这一设计模式在链表问题中广泛应用,例如:

  • 反转链表
  • 删除链表节点
  • 合并多个有序链表

掌握虚拟头节点的使用,能让你在处理链表问题时更高效、优雅。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值