给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reorder-list/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
感谢编程狂想曲的动画演示快慢指针 143. 重排链表
class Solution {
public void reorderList(ListNode head) {
reorderListII(head);
reorderListI(head);
}
//方法二:三个步骤
//先找到链表的中间结点,将中间节点之后的链表进行反转
//将链表的前半部分和反转后的部分进行合并
//时间复杂度O(N),空间复杂度O(1)
private void reorderListII(ListNode head) {
if (head == null || head.next == null) {
return;
}
ListNode mid = getMiddle(head);
ListNode right = mid.next;
//将mid后链表断开,便于反转
mid.next = null;
right = reverse(right);
//合并链表
merge(head, right);
}
private ListNode getMiddle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode reverse(ListNode head) {
ListNode prev = null;
ListNode cur = head;
while (cur != null) {
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
private void merge(ListNode left, ListNode right) {
ListNode p1 = null;
ListNode p2 = null;
while (left != null && right != null) {
p1 = left.next;
p2 = right.next;
//连接两个链表,例如left=1,2,right=4,3,连接后left变为1,4,2,3
left.next = right;
left = p1;
right.next = p1;
right = p2;
}
}
//方法一:使用List存储
//先将链表保存到List中
//定义两个指针,遍历list,分别进行节点的交换
//时间复杂度O(N),空间复杂度O(N)
private void reorderListI(ListNode head) {
List<ListNode> list = new ArrayList<>();
while (head != null) {
list.add(head);
head = head.next;
}
int left = 0, right = list.size() - 1;
while (left < right) {
list.get(left).next = list.get(right);
left++;
//偶数节点情况下
if (left == right) {
break;
}
list.get(right).next = list.get(left);
right--;
}
//将链表尾节点置为null
list.get(left).next = null;
}
}