反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-linked-list-ii
解题思路
首先解决翻转整个链表的问题,给定一个头节点,将其所在链表翻转
需要有三个变量来记录翻转过程,pre
cur
next
分别代表原顺序的"上一个" "当前这个" "下一个"
现将cur
置为头节点,pre
置为空
当cur
不为空时循环
- 记录
next
为cur.next
-
cur.next = pre
将当前节点的下一个指向前一个节点 pre = cur
-
cur = next
后面两步起到迭代的作用
循环结束时pre就是新的头节点
然后解决翻转一个链表中的一部分
需要将链表分为三部分,翻转的前驱部分,翻转部分,翻转的后继部分
为了方便处理m = 1
也就是从头结点开始翻转这种情况,使用一个假的头结点dummy
使dummy.next = head
然后从dummy
开始往后找n
次,找到翻转部分的尾节点,记录该尾节点的后继节点nextNode
,以便翻转后连接上翻转的后继部分
接着从dummy
开始往后找m - 1
次,找到翻转的前驱部分的尾节点并记录,该节点的next
就是翻转部分的头节点
将翻转部分的头节点传给翻转方法,传递参数的头节点在翻转后变为尾节点,将该节点的next
设为上述记录的nextNode
翻转方法返回节点是翻转后的翻转部分头节点,所以翻转的前驱部分的尾节点的next
设为该节点
返回dummy.next
代码
class Solution {
private ListNode reverse(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
public ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null || head.next == null || m == n) {
return head;
}
// 辅助头节点
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode cur = dummy;
// 找出要翻转部分的尾节点
for (int i = 0; i < n; i++) {
cur = cur.next;
}
// 结束for后cur是要翻转的尾节点
// 保存该节点的后继
ListNode next = cur.next;
// 断开以便反转
cur.next = null;
cur = dummy;
// for结束后cur的下一个是要翻转的部分的头节点
for (int i = 0; i < m - 1; i++) {
cur = cur.next;
}
ListNode start = cur.next;
// 翻转后start是翻转部分的尾节点
ListNode reverseHead = reverse(cur.next);
cur.next.next = next;
cur.next = reverseHead;
return dummy.next;
}
}