Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes' values.
For example,
最好的解法:
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-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}.
典型的考察链表操作基本功的题目,对于链表的操作无非两个最基本的:插入和删除,这里要求按照给定的方式,将链表重新排序,由于排序之后,Ln要排到Ln-1之前,但是所给出的结点数据结构里没有保存当前结点前驱结点的指针,同时算法不允许投机取巧改变结点的值。
最一般的思想:如果每次都去找Ln...Ln-1...的位置在去执行题目要求的操作,那么每次找到需要向前插入的节点需要O(n),总共需要插入O(n)次,时间复杂度是O(n2),空间复杂的O(1);
进一步思考(我的解法):如果实现吧所有节点的地址都保存下来记为指针数组pointers[n],那么在操作过程中只需要对数组中的节点进行操作就可以了,省去了每次查找"Ln"节点的时间,由此时间复杂度O(n),空间复杂度O(n);
再进一步(这个事看别人的):在Discuss板块中,有人给出的算法,将后一半的链表执行倒序操作,然后在将被分解的两部分合并起来就可以了,时间复杂度O(n),空间复杂度O(1):
我的解法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
if (head==NULL)
{
return ;
}
//思路:
//创建一个等于链表长度的指针数组,保存链表中每个元素的指针
//然后按照要求进行调整
//双向遍历指针数组
ListNode *ptop=head;
ListNode *pbuttom=head;
ListNode **pPointerArray;
int arraySize=0;
while (pbuttom!=NULL)
{
pbuttom=pbuttom->next;
arraySize++;
}
pPointerArray=new ListNode*[arraySize];
pbuttom=head;
int i=0;
while (pbuttom!=NULL)
{
pPointerArray[i]=pbuttom;
i++;
pbuttom=pbuttom->next;
}
i=0;
int j=arraySize-1;
while (i<j)
{
//cut j
pPointerArray[j-1]->next=pPointerArray[j]->next;
//insert j to i next
pPointerArray[j]->next=pPointerArray[i]->next;
pPointerArray[i]->next=pPointerArray[j];
i++;
j--;
}
delete[] pPointerArray;
}
};
最好的解法:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
//void reorderList(ListNode *head) {
// if (head==NULL)
// {
// return ;
// }
// //思路:
// //创建一个等于链表长度的指针数组,保存链表中每个元素的指针
// //然后按照要求进行调整
// //双向遍历指针数组
// ListNode *ptop=head;
// ListNode *pbuttom=head;
// ListNode **pPointerArray;
// int arraySize=0;
// while (pbuttom!=NULL)
// {
// pbuttom=pbuttom->next;
// arraySize++;
// }
// pPointerArray=new ListNode*[arraySize];
// pbuttom=head;
// int i=0;
// while (pbuttom!=NULL)
// {
// pPointerArray[i]=pbuttom;
// i++;
// pbuttom=pbuttom->next;
// }
//
// i=0;
// int j=arraySize-1;
// while (i<j)
// {
// //cut j
// pPointerArray[j-1]->next=pPointerArray[j]->next;
// //insert j to i next
// pPointerArray[j]->next=pPointerArray[i]->next;
// pPointerArray[i]->next=pPointerArray[j];
// i++;
// j--;
// }
//
// delete[] pPointerArray;
//}
void reorderList(ListNode *head) {
if (head==NULL)
{
return ;
}
//calculate the length of the list
ListNode *pCurrent=head;
int ListLen=0;
while (pCurrent!=NULL)
{
ListLen++;
pCurrent=pCurrent->next;
}
if (ListLen==1)
{
return;
}
//partation
int halpLen=ListLen-ListLen/2;
ListNode *pSecond=head;
ListNode *pPreSecond=NULL;
for (int i=0;i<halpLen;i++)
{
pPreSecond=pSecond;
pSecond=pSecond->next;
}
pPreSecond->next=NULL;
//reverse Second half
pPreSecond=pSecond;
pSecond=pSecond->next;
pPreSecond->next=NULL;
ListNode *pPostSecond;
while (pSecond!=NULL)
{
//存储正序表下一个头节点
pPostSecond=pSecond->next;
//从正序表断开当前节点
pSecond->next=pPreSecond;
//更新逆序表头节点
pPreSecond=pSecond;
//保证pSecond始终指向正序表头
pSecond=pPostSecond;
}
pSecond=pPreSecond;
ListNode *pFirst=head;
while (pSecond!=NULL)
{
//保存后半部分逆序表头节点
pPostSecond=pSecond->next;
//将节点插入对应位置
pSecond->next=pFirst->next;
pFirst->next=pSecond;
//更新下次待操作节点
pFirst=pSecond->next;
pSecond=pPostSecond;
}
}
};