算法通关村第二关——指定区间反转链表问题解析
题目为Leetcode 92
给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表。
输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]
解法一:穿针引线法
找到要反转的区间,截取该部分先将这部分反转后再拼接回原始的链表
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode pre = dummyHead;
//指向left的前一个结点
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode rightNode = pre;
//指向right结点
for (int i = 0; i < right - left + 1; i++) {
rightNode = rightNode.next;
}
//截取待反转链表
ListNode leftNode = pre.next;
ListNode cur = rightNode.next;
pre.next = null;
rightNode.next = null;
//反转链表
reverseList(leftNode);
//拼接
pre.next = rightNode;
leftNode.next = cur;
return dummyHead.next;
}
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
解法二:头插法
方法一存在缺点:如果 left 和 right 的区域很大,恰好是链表的头节点和尾节点时,找到 left 和 right 需要遍历一次,反转它们之间的链表还需要遍历一次,虽然总的时间复杂度为 O(N),但遍历了链表 2 次
思路:在遍历到需要反转的区间时,每遍历到一个新节点就让该节点移动到反转区间的起始位置(left)
完整代码
public ListNode reverseBetween2(ListNode head, int left, int right) {
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
ListNode pre = dummyHead;
// 将pre指向待反转区间第一个结点的前一个结点
for (int i = 0; i < left - 1; i++) {
pre = pre.next;
}
ListNode cur = pre.next; //指向待反转区间的第一个结点
ListNode next; //指向cur的下一个结点
for (int i = 0; i < right - left; i++) {
next = cur.next;
cur.next = next.next;
next.next = pre.next;
pre.next = next;
}
return dummyHead.next;
}