给定一个链表,把最后一个结点插入到第1个结点后,倒数第二个结点插入到第2个结点后,倒数第三个结点插入到第3个结点后,以此类推……
【必须在不改变节点值的情况下就位】
思路:
先用快慢指针找到链表的中点,然后翻转链表后半部分,再和前半部分组合。
注意:
把链表分成两半时,前半段的尾节点要置为NULL,翻转链表时也要把尾节点置为NULL。
/**
* 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)
return;
ListNode *fast=head;
ListNode *slow=head;
while(fast->next && fast->next->next){
fast=fast->next->next;
slow=slow->next;
}
//此时的slow即为中间节点
//将中间节点前后拆成两条链
ListNode *list=slow->next;
slow->next=NULL;
//逆置中间节点后的节点
ListNode *node=NULL;
ListNode *cur=list;
while(cur){
ListNode *tmp=cur;
cur=cur->next;
//头插头插法
tmp->next=node;
node=tmp;
}
list=node;
//将两个链表合并
ListNode *node1=head,*node2=list;
while(node2){
ListNode *tmp1=node1->next;
ListNode *tmp2=node2->next;
node1->next=node2;
node2->next=tmp1;
node1=tmp1;
node2=tmp2;
}
}
};
因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。
时间复杂度O(nlogn)空间复杂度 O(1)
归并排序的一般步骤为:
- 将待排序数组(链表)取中点并一分为二;
- 递归地对左半部分进行归并排序;
- 递归地对右半部分进行归并排序;
根据题目要求,可以划分为三个小问题:
- 找到链表中点
- 写出MergeTwoList函数,即如何合并链表。
- 写出sortlist函数,通过递归实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *FindMiddleNode(ListNode *head){
ListNode *fast=head,*slow=head;
while(fast->next && fast->next->next){
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
ListNode *MergeTwoList(ListNode *list1,ListNode *list2){
if(list1==NULL)
return list2;
if(list2==NULL)
return list1;
ListNode *list=new ListNode(NULL),*node=list;
while(list1 && list2){
if(list1->val>list2->val){
node->next=list2;
list2=list2->next;
}else{
node->next=list1;
list1=list1->next;
}
node=node->next;
}
if(list1)
node->next=list1;
if(list2)
node->next=list2;
return list->next;
}
ListNode *sortList(ListNode *head) {
if(head==NULL || head->next==NULL)
return head;
ListNode *middle=FindMiddleNode(head);
ListNode *right=sortList(middle->next);
middle->next=NULL;
ListNode *left=sortList(head);
return MergeTwoList(left,right);
}
};
给出一个所有元素以升序排序的单链表,将它转换成一棵高度平衡的二分查找树
用快慢指针找出中点,作为根,中点左右两边分别递归的构建二叉树。
最初使用跟Sort List一般的方法:一个链分裂成两个链,发现有错误。原因是有中点需要去掉,跟划分链不完全一致了。
最好是使用一个begin指针指示第一个元素,end指针指示最后一个元素的下一个位置(即左闭右开空间),很方便的就构建起平衡二叉树。
元素个数为奇数的构建平衡二叉查找树:
元素个数为偶数的构建平衡二叉查找树:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode *BuildBSTree(ListNode *begin,ListNode *end){
if(begin==end)
return NULL;
ListNode *fast=begin,*slow=begin;
while(fast->next!=end && fast->next->next!=end){
fast=fast->next->next;
slow=slow->next;
}
fast=slow->next;
TreeNode *root=new TreeNode(slow->val);
root->left=BuildBSTree(begin,slow);
root->right=BuildBSTree(fast,end);
return root;
}
TreeNode *sortedListToBST(ListNode *head) {
if(head==NULL)
return NULL;
if(head->next==NULL)
return new TreeNode(head->val);
return BuildBSTree(head,NULL);
}
};