我的LeetCode代码仓:https://github.com/617076674/LeetCode
原题链接:https://leetcode-cn.com/problems/reorder-list/description/
题目描述:
知识点:双指针、链表
思路:用快慢双指针遍历链表区分链表的前半部分和后半部分
借鉴LeetCode141——环形链表和LeetCode142——环形链表II中的思路二,我们用快慢双指针遍历链表以区分链表的前半部分和后半部分。参照代码,慢指针cur2移动一步,则快指针cur3移动2步。
以示例1为例(链表中节点个数是偶数个):-1 -> 1 -> 2 -> 3 -> 4,其中-1是我们设立的虚拟头节点,也是cur2和cur3指针的共同起点。当cur3到达4节点时,遍历结束,此时cur2在2节点,其后半部分节点从cur2.next节点开始。
以示例2为例(链表中节点个数是奇数个):-1 -> 1 -> 2 -> 3 -> 4 -> 5,其中-1是我们设立的虚拟头节点,也是cur2和cur3指针的共同起点。当cur3到达4节点时,遍历结束,此时cur2在3节点,其后半部分节点也从cur2.next节点开始。
因此无论链表中节点个数的奇偶性,在cur2和cur3移动结束后,其后半部分节点均是从cur2.next节点开始的。
我们将链表分成两部分,第一部分是cur2.next节点之前的节点,第二部分是cur2.next及其之后的节点。
接下来我们只需反转第二部分节点,关于反转链表的方法,可以参考LeetCode206——反转链表,本题的实现中使用了非递归的方式反转链表。
最后,我们只需根据题意,用两部分节点拼接出我们需要的新链表即可。
时间复杂度是O(n),其中n为链表中的节点个数。空间复杂度是O(1)。
JAVA代码:
public class Solution {
public void reorderList(ListNode head) {
//设立虚拟头节点
ListNode dummyHead = new ListNode(-1);
dummyHead.next = head;
//cur1指向链表头节点
ListNode cur1 = head;
//cur2,cur3是快慢双指针,cur2移动一步,cur3移动两步
ListNode cur2 = dummyHead;
ListNode cur3 = dummyHead;
while(cur3 != null && cur3.next != null) {
cur2 = cur2.next;
cur3 = cur3.next.next;
}
cur2 = cur2.next;
//寻找cur2的父节点preCur2
ListNode preCur2 = dummyHead;
while(preCur2.next != cur2) {
preCur2 = preCur2.next;
}
preCur2.next = null;
//反转后半段链表
ListNode newHead = reverseLinkedList(cur2);
ListNode newCur1 = newHead;
//组合出新链表
while(cur1 != null && newCur1 != null) {
ListNode nextCur1 = cur1.next;
ListNode nextNewCur1 = newCur1.next;
cur1.next = newCur1;
newCur1.next = nextCur1;
newCur1 = nextNewCur1;
cur1 = nextCur1;
}
}
private ListNode reverseLinkedList(ListNode head) {
if(head == null || head.next == null) {
return head;
}
ListNode pre = null;
ListNode cur = head;
ListNode next = cur.next;
while(cur != null) {
cur.next = pre;
pre = cur;
cur = next;
if(cur != null) {
next = cur.next;
}
}
return pre;
}
}
LeetCode解题报告: