题目
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回反转后的链表。
题目来源:LeetCode92.反转链表 II
题解
方法:头插法
思路
用 pre 记录位置 left 的前一个结点,用 curr 记录所在位置为 left 的结点,用 next 记录 curr 所指向的下一个节点,在指定区间进行反转相当于将 curr 后的结点依次插入到 pre 所记录结点的前面,right - left 即为 curr 后有多少个结点需要进行该插入操作。
该过程示例如下图所示:
Java 代码实现
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode curr = pre.next;
ListNode next;
for (int i = 0; i < right - left; i++) {
next = curr.next;
curr.next = next.next;
next.next = pre.next;
pre.next = next;
}
return dummyNode.next;
}
代码中 dummyNode 的作用主要有两点:
1、保护首节点:如果反转的部分包括了首节点,即 left = 1,在反转过程中,首节点会变更。如果没有 dummyNode,我们将无法保留原链表的首节点,从而无法返回完整的链表。而 dummyNode 的下一个节点始终指向链表的首节点,无论首节点如何变化,我们都可以通过 dummyNode.next 来获得新链表的首节点。
2、统一处理逻辑:在链表问题中,插入或删除节点时,需要修改前一个节点的 next 指针,这在首节点处是一个特殊情况,因为它没有前一个节点。dummyNode 被用作首节点的前一个节点,使得对首节点的操作可以和对其他节点的操作一样处理,这样就无需单独编写处理首节点的逻辑,使代码更简洁。
因此, dummyNode 有时也被称为 “哨兵节点” 或 “哑节点”,它在处理链表问题时可以帮助我们避免处理一些边界条件,使得代码实现更为清晰和简洁。
总结
本文使用头插法解决了链表中指定区间反转的问题,用该方法进行反转操作的关键在于要弄清楚需要将哪些结点插入到哪个位置上,在结点插入的过程中需要捋清楚各结点指向改变的先后顺序,所以本质上还是在考察链表的插入操作。
获取本文全部示例代码文件
本文全部示例代码文件可从我的 GitHub 仓库中获取:算法通关村第二关——指定区间反转问题解析代码