这个题目让我想起上个月做的Reverse List in K-group。LeetCode上一定还有许多有关的题目。我曾自认为链表是基础数据结构里最简单的了。加上大三下学期写了一个二叉树的谓词逻辑的人工智能作业,觉得这一块还挺熟练的。其实都是错觉啊!
刚开始好笨的,直接这么做的
void reorderList(ListNode *head) {
ListNode* curHead = head, *nextHead = NULL;
while(curHead != NULL){
ListNode* pretail = curHead;
if(curHead->next == NULL || curHead->next->next == NULL)
return;
while(pretail->next->next!=NULL) pretail = pretail->next;
//printf("tail=%d\n",tail->val);
nextHead = curHead->next;
curHead->next = pretail->next;
pretail->next->next = nextHead;
pretail->next = NULL;
curHead = nextHead;
}
}
每次拿出头拿出尾连到一起。我复杂度分析学的不好,不知这个算不算是一个O(n!)复杂度的?我还是提交了然后超时了,才仔细思考自己写的是不是太麻烦。
为了避免每次找链表尾都要从头开始往后走,想到了用数组存起来,两个指针i、j从一头一尾出发。网上也有人这么写。
void reorderList(ListNode *head) {
if(head==NULL) return;
vector<ListNode*> q;
ListNode* curHead = head;
while(curHead){
q.push_back(curHead);
curHead = curHead->next;
}
int len = q.size();
int j = 0, k = len - 1;
while(j < k){
q[j++] -> next = q[k];
q[k--] -> next = q[j];
//q[k] -> next = NULL;
//printf("j=%d, k=%d\n",j,k);
}
q[j] -> next = NULL;
}
本来想用纯数组,但是不知道测试数据量有多大(估计很大),开到100000还run time error,可能是越界了吧。所以就用vector好了。该开始,q[j] -> next = NULL;这句话我是没有的,而是在循环里最后一句是q[k] -> next = NULL;,参考了网上的写法就挪到外面来了。必须这么做,否则如果处理到只剩最后两个节点时会出错(比如{1,2}输出{1})。如果没错的话,这个应该是O(n)复杂度吧?304ms。
接下来又看到有人写的挺优美(点击打开链接),用到了一个快慢指针,把链表分成两部分,后半部分翻转并与前半部分合并。感觉也是个O(n)呀,但是比前一个方法还稍快一点。
void reorderList(ListNode *head) {
if(head == NULL){
return;
}
ListNode* p1 = head;
ListNode* p2 = splitList(head);
mergeList(p1, revertList(p2));
}
void mergeList(ListNode * p1, ListNode * p2){
while(p2 != NULL){
ListNode* tmp = p2;
p2 = p2->next;
tmp->next = p1->next;
p1->next = tmp;
p1 = p1->next->next;
};
}
ListNode* splitList(ListNode *head){
ListNode* slow = new ListNode(0);
slow->next = head;
ListNode* fast = slow;
while(fast->next != NULL && fast->next->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
if(fast->next != NULL){
slow = slow->next;
fast = fast->next;
}
ListNode* tmp = slow->next;
slow->next = NULL;
return tmp;
}
ListNode* revertList(ListNode* head){
if(head == NULL){
return NULL;
}
ListNode* p = head->next;
head->next = NULL;
while(p != NULL){
ListNode* tmp = p;
p = p->next;
tmp->next = head;
head = tmp;
}
return head;
}
其实上边的代码并不难。链表难在指针的处理顺序,特殊情况的考虑等,很麻烦。