题干
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,
Given{1,2,3,4}, reorder it to{1,4,2,3}.
链表结构修改。要求in-place,不能使用辅助数据结构。
数据结构
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
解题思路
这个题有两个思路:
1.两个指针,第一个指针指示当前要添加结点的位置,第二个指针一直遍历得到当前链表尾结点。将尾结点插入到当前结点后面。
2.三步走:
a.找到链表中间结点:用两个指针遍历,一个指针一次走一步,一个两步。
b.反转后半部分链表结点。
c.将后半部分结点插入前半部分结点。
参考代码
方法一:
class Solution {
public:
void reorderList(ListNode *head) {
ListNode *cur=head;//当前结点
ListNode *tmp;
while(head!=NULL&&head->next!=NULL){
while(cur->next->next!=NULL){
cur=cur->next;
}
tmp=cur->next;//结点添加,画一下就可以明白具体过程
cur->next=NULL;
tmp->next=head->next;
head->next=tmp;
head=cur=tmp->next;
}
}
};
方法二:
class Solution {
public:
void reorderList(ListNode *head) {
if (head==NULL||head->next==NULL)
return;
ListNode *p1=head,*p2=head;
//第一步:找到中间点
while(p2->next!=NULL&&p2->next->next!=NULL){
p1=p1->next;
p2=p2->next->next;
}
ListNode *tmp;
ListNode *mid=p1;
ListNode *pre_head=new ListNode(0);//建立伪头,方便进行操作
pre_head->next=mid->next;
ListNode *cur=pre_head->next;
//第二步:反转后半部分链表
while (cur->next!=NULL) {
ListNode *tmp=pre_head->next;
pre_head->next=cur->next;
cur->next=pre_head->next->next;
pre_head->next->next=tmp;
}
p1=head;
p2=pre_head->next;
//第三步:合并前后两部分链表
while(p1!=mid){
mid->next=p2->next;
p2->next=p1->next;
p1->next=p2;
p1=p2->next;
p2=mid->next;
}
}
};
方法讨论
根据代码直观可以得到,方法一代码简单但是算法复杂度较高为O(n²),第二种方法代码复杂但是算法复杂度比较低为O(n)。
易错点
边界条件
找中间结点,反转等处边界条件。