将给定的单链表L: L 0→L 1→…→L n-1→L n, 重新排序为: L 0→L n →L 1→L n-1→L 2→L n-2→…
要求使用原地算法,并且不改变节点的值 例如: 对于给定的单链表{1,2,3,4},将其重新排序为{1,4,2,3}.
我的思路是:
- 先找到中间结点
- 将后半段翻转
- 将后半段节点依次插入
这几项的实现方法为:
-
快慢指针。快指针一次走两步,慢指针一次走一步。快指针的速度是慢的两倍,快指针到末尾的时候,慢指针正好到中间。(妙啊!)
while(fast->next!=nullptr&&fast->next->next!=nullptr) {// 这个判断注意顺序,一个next要写在两个next之前
slow = slow->next;
fast = fast->next->next;
}
-
翻转。没什么好说的
-
依次插入。注意后半段一定要单独出来,即:
se = slow->next;
fi = head;
slow->next = nullptr;
完整代码:
/**
* 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==nullptr||head->next==nullptr||head->next->next==nullptr)
return ;
ListNode *slow,*fast;//中间
slow = head;
fast = head;
while(fast->next!=nullptr&&fast->next->next!=nullptr) {// 这个判断注意顺序,一个next要写在两个next之前
slow = slow->next;
fast = fast->next->next;
}
//printf("%d\n",slow->data);
ListNode *m,*p;//翻转
m = slow->next;
while(m->next!=nullptr){
p = m->next;
m->next = p->next;
p->next = slow->next;
slow->next = p;
}
ListNode *se,*fi,*tem;//合并
se = slow->next;
fi = head;
slow->next = nullptr;
while(fi!=nullptr&&se!=nullptr){
tem = se;
se = se->next;
tem->next = fi->next;
fi->next = tem;
fi = fi->next->next;
}
}
};
还有一种暴力解法也贴一下,时间复杂度有点高,退出条件也需要想一想,不过就很简短哈哈 爽
class Solution {
public:
void reorderList(ListNode *head) {
if(head==nullptr||head->next==nullptr||head->next->next==nullptr)
return ;
ListNode *p,*m,*q;
p = head;
m = p;
q = m;
while(p->next!=m && p->next!=nullptr){
m = head->next;
while(m->next->next!=nullptr){
m = m->next;
}
q = m->next;
m->next = NULL;
q->next = p->next;
p->next = q;
p = q->next;
}
return ;
}
};