题目描述
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表
示例:
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
一、思路解析
由于此题可能涉及到头节点,也可能不涉及头节点,故建议创建一个虚拟节点,统一所有节点的处理,比较方便。核心解题思路有两种:
-
头插法:找到left - 1的节点,将left后面的节点挨个拿下来插入到left - 1 和 left之间。
-
穿针引线法:找到left - 1、left、right、right + 1节点,将left和right部分单独反转,然后重新拼接链表。
下面针对这两种方式给出代码参考。
二、代码演示
class ListNode{
public int data;
public ListNode next;
public ListNode(int data) {
this.data = data;
this.next = null;
}
}
方法一:头插法
private ListNode reverseBetween(ListNode head, int left, int right) {
// 1. 建立虚拟节点
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
// 2. 找到left - 1节点
ListNode pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
// 3. 头插
ListNode cur = pre.next;
ListNode next;
for (int i = 0; i < right - left; i++) {
next = cur.next;
cur.next = next.next;
// 节点会不断插入到pre后面,pre.next会不断变化,cur一直是left节点不变,故此处不能用cur而应该用pre.next
next.next = pre.next;
pre.next = next;
}
return dummyNode.next;
}
方法二:穿针引线法
private ListNode reverseBetween(ListNode head, int left, int right) {
// 1. 建立虚拟节点
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
// 2. 找到left - 1、left、right和right + 1节点,切割区间链表
ListNode pre = dummyNode;
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode leftNode = pre.next;
ListNode rightNode = leftNode;
for (int i = 0; i < right - left; i++) {
rightNode = rightNode.next;
}
ListNode succ = rightNode.next;
// 非常重要,翻转区间链表的时候条件判断是cur != null,防止将后面链表也翻转了
rightNode.next = null;
// 3. 反转区间链表
reverseLinkedList(leftNode);
// 4. 连接链表:leftNode和rightNode的指向没有改变,只是链表顺序改变了,故还可以使用。
pre.next = rightNode;
leftNode.next = succ;
return dummyNode.next;
}
private ListNode reverseLinkedList(ListNode head) {
ListNode pre = null, cur = head;
ListNode next;
while (cur != null) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
注:区间链表的反转之前博客有介绍,此处采用第二种直接操作链表实现。若有疑问,可以参考:单链表反转
三、总结
- 头插法的实现思路主要是不断将left + 1的节点不断往前插,让left + 2节点变成新的left + 1节点。注意pre和cur节点一直没有变,只是cur不断被挤到后面,pre.next在不断变化。
- 穿针引线法的实现思路主要是将原链表分成了反转链表前、反转链表、反转链表后三部分进行操作,需要注意的是,反转链表部分right节点的next需要设置成null,不然会将反转链表后的部分也一并反转了。
以上皆为个人愚见,欢迎补充更好的方法~~ 如有不足之处,也请不吝赐教,帮忙指正,谢谢!