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; } } };