题目描述
将给定的单链表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}.
Given a singly linked list L: L 0→L 1→…→L n-1→L n,
reorder it to: L 0→L n →L 1→L n-1→L 2→L n-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 algorithm)基本上不需要额外辅助的数据结构,然而,允许少量额外的辅助变量来转换数据的算法。当算法运行时,输入的数据通常会被要输出的部分覆盖掉。不是原地算法有时候称为非原地(not-in-place)或不得其所(out-of-place)。
思路:
- 要求使用原地算法,那就不能利用栈等数据结构;
- 利用cur指针和last指针作为索引分别指向头尾即将要插入的结点,插入过的结点就从链表中删除;
- 当链表的长度小于等于2时,完成最后一次插入;
- 注意到GetLastTwo函数返回的是链表的倒数第二个结点,这么做的目的是更方便的删除最后一个结点。
代码:
/**
* 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 || head->next == NULL || head->next->next == NULL)
return;
ListNode *cur = head->next;
ListNode *last = GetLastTwo(cur);
ListNode *tem = head;
while (last && cur != last)
{
tem->next = last->next;
last->next = NULL;
tem = tem->next;
tem->next = cur;
cur = cur->next;
tem = tem->next;
last = GetLastTwo(cur);
}
if (last == NULL)
{
tem->next = cur;
cur->next = NULL;
}
else
{
tem->next = cur->next;
tem = tem->next;
tem->next = cur;
cur->next = NULL;
}
return;
}
ListNode *GetLastTwo(ListNode *head) // 取倒数第二个结点
{
if (head == NULL || head->next == NULL)
return NULL;
while (head->next->next != NULL)
{
head = head->next;
}
return head;
}
};
运行时间:254ms,占用内存:1760k。
之后看了大神们的思路,大多是利用快慢指针找到中间结点,对后半部分逆序,再合并两个链表。学习了~
代码:
/**
* 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 || head->next == NULL || head->next->next == NULL)
return;
//快慢指针找中点
ListNode* fast = head;
ListNode* low = head;
while(fast->next != NULL && fast->next->next != NULL){
fast = fast->next->next;
low = low->next;
}
//对low后面的部分逆序
fast = low->next;
low->next = NULL;
while(fast != NULL){
ListNode* temp = fast->next;
fast->next = low->next;
low->next = fast;
fast = temp;
}
//合并low前面和后面两部分
ListNode* p = head;
ListNode* q = low->next;
while(p != NULL && q != NULL){
low->next = q->next;
q->next = p->next;
p->next = q;
p = q->next;
q = low->next;
}
}
运行时间:23ms,占用内存:1796k。