[LeetCode] 重排链表 reorder linked list

本文介绍了一种将链表L0→L1→…→Ln-1→Ln重排序为L0→Ln→L1→Ln-1→L2→Ln-2→…的算法实现。通过找到链表中点、反转后半部分链表并插入到前半部分链表的相应位置来完成重排序。提供了完整的C++代码实现。

Given a singly linked list LL0L1→…→Ln-1Ln,
reorder it to: L0LnL1Ln-1L2Ln-2→…

You must do this in-place without altering the nodes' values.

For example,

Given {1,2,3,4}, reorder it to {1,4,2,3}.

Analysis:


Let's see some examples:

{1,2,3,4,5,6} ---> {1,6,2,5,3,4}
{1,2,3,4,5,6,7} ---> {1,7,2,6,3,5,4}

One straightforward middle step of such reordering is:
{1,2,3,4,5,6}  --> {1,2,3,6,5,4} --> {1,6,2,5,3,4}
{1,2,3,4,5,6,7}---> {1,2,3,4,7,6,5} ---> {1,7,2,6,3,5,4}

By reversing the last part of the linked list, we do not need to worried about the "parent" pointer anymore. The final step is just insert the each element in the last part into the first part (every two element).

So the algorithm implemented below can be summarized as:
Step 1  Find the middle pointer of the linked list (you can use the slow/fast pointers)
Step 2  Reverse the second part of the linked list (from middle->next to the end)
Step 3  Do the reordering. (inset every element in the second part in between the elements in the first part)

下面是代码。要注意的是:1)第24和25行,fast pointer被初始化成slow pointer的下一个。(自己在纸上画一下,这样初始化的结果是什么)。不能把fast pointer 和slow pointer都初始化成head节点。

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
#include <string.h>

#include <stack>
#include <stdio.h>
#include <stdlib.h>

struct ListNode {
     int data;
     ListNode *next;
     ListNode(int x, ListNode* nex) : data(x), next(nex) {}
};

ListNode* reverseList(ListNode* head);
void printLL(ListNode* head);

void reorderList(ListNode *head) {
	if(head==NULL || head->next == NULL || head->next->next==NULL)
		return;

	ListNode* slow = head;
	ListNode* fast = head->next; // fast should be the next of slow

	while(fast)
	{
		if(fast->next)	fast = fast->next;
		else break;

		if(fast->next) fast = fast->next;
		else break;		

		if(slow==NULL) slow = head;
		else slow = slow->next;
	}

	reverseList( slow->next );
	slow->next = NULL;

	ListNode* cur1 = head;
	ListNode* cur2 = fast;
	while(cur1)
	{
		ListNode* nex1 = cur1->next;
		ListNode* nex2 = cur2->next;

		cur1->next = cur2;
		if(nex1 == NULL)
		{
			cur2->next = nex2;
			break;
		}
		else
			cur2->next = nex1;

		cur1 = nex1;
		cur2 = nex2;	
	}	
}

ListNode* reverseList(ListNode* head)
// reverse a linked list
{
	if(head==NULL)
		return head;
 	if(head->next == NULL)
		return head;

	ListNode* tmp = reverseList(head->next);
	tmp->next = head;
	head->next = NULL;
	return head;
}

void printLL(ListNode* head)
{
	while(head)
	{
		cout<<head->data<<" ";
		head = head->next;
	}
}

int main()
{
	ListNode* n0 =new ListNode(0, NULL);
	ListNode* n1 =new ListNode(1, n0);
	ListNode* n2 =new ListNode(2, n1);
	ListNode* n3 =new ListNode(3, n2);
	ListNode* n4 =new ListNode(4, n3);
	ListNode* n5 =new ListNode(5, n4);
	ListNode* n6 =new ListNode(6, n5);
	ListNode* n7 =new ListNode(7, n6);

	reorderList(n7);
	printLL(n7);
}


### LeetCode 重排链表 解题思路和方法 #### 方法1——线性表辅助 ##### 思路分析 为了简化操作,可以先遍历整个链表并将所有节点存储在一个列表中。之后按照新顺序重新连接这些节点即可。这种方法虽然额外使用了O(n)的空间来保存节点指针,但是逻辑简单易懂。 对于给定的单链表 L:L0→L1→…→Ln-1→Ln ,将其重新排列后变为:L0→Ln→L1→Ln-1→L2→Ln-2→… 此过程可以通过创建一个数组来暂存所有的节点,再通过双指针的方式从前向后以及从后向前交替取出节点并构建新的链接关系[^1]。 ```python def reorderList(self, head: ListNode) -> None: if not head or not head.next: return nodes = [] current = head while current: nodes.append(current) current = current.next left, right = 0, len(nodes) - 1 last = head while left < right: nodes[right].next = nodes[left].next nodes[left].next = nodes[right] last = nodes[left] left += 1 right -= 1 last.next = None ``` #### 方法2——中间节点+反转链表+合并链表 ##### 思路分析 该方案旨在优化空间复杂度至 O(1),即不借助额外的数据结构完成任务。具体步骤如下: 1. 找到原链表的中间位置; 2. 对从中点开始直到结尾的部分执行逆序处理; 3. 将前半部分与经过翻转后的后半部分依次交错相连形成最终的结果链表[^2]。 找到链表中心的方法是利用快慢两个指针同时出发,当快速指针到达终点时,慢速指针正好位于中部;而针对长度为奇数的情况,则让较短的一侧多保留一个元素作为起始点[^4]。 ```python def reorderList(self, head: ListNode) -> None: if not head or not head.next: return # 寻找链表中点 slow, fast = head, head while fast and fast.next: slow = slow.next fast = fast.next.next # 反转后半部分链表 prev, curr = None, slow.next while curr: next_temp = curr.next curr.next = prev prev = curr curr = next_temp slow.next = None # 合并两部分链表 first_half, second_half = head, prev while second_half: temp1, temp2 = first_half.next, second_half.next first_half.next = second_half second_half.next = temp1 first_half, second_half = temp1, temp2 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值