24. Swap Nodes in Pairs
题意:交换两个相邻的节点,不够就不交换。
思路:设置一个pre节点,用来控制上一组节点和下一组节点的连接,维护后该节点就行,可以通过画图来思考。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode p(INT_MIN);
ListNode* tmp1=&p,*tmp2;
tmp1->next=head;
head=tmp1;
while(tmp1->next!=NULL && tmp1->next->next!=NULL)
{
tmp2=tmp1->next->next; //获得下一个节点
tmp1->next->next=tmp2->next;
tmp2->next=tmp1->next;
tmp1->next=tmp2;
tmp1=tmp2->next;
}
return head->next;
}
};
25. Reverse Nodes in k-Group
题意:转置k个节点,不够k个不转。
思路:因为是k个节点,k未知,所以要求出总共有多少个点,才能保证不会处理节点数不够k个的情况。第24题不用求总数是因为k已知。要控制维护第一个节点的前一个节点,节点顺序改变和上一题一样。
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode l(-1),*pre=&l,*cur=pre;
pre->next=head;
int num=0;
while(cur=cur->next) num++;
while(num>=k)
{
cur=pre->next;
for(int i=1;i<k;i++)
{
ListNode* t=cur->next;
cur->next=t->next;
t->next=pre->next;//这里是pre->next,不能是cur,可自行验证。
pre->next=t;
}
pre=cur;
num-=k;
}
return l.next;
}
};
147. Insertion Sort List
题意:利用插入排序的思想来排序一个List。
思路:插入排序只在一个有序序列中插入一个数,插入后仍然有序。如果试图去遍历List来找最小值排序显然将花费大量时间且不是插入排序的思想。所以我们将一个List分为两部分,一部分为已排序的,一部分为未排序的,只要维护好已排序的,然后遍历未排序的插入就行。我们将第一个节点视为已排序好,直接从下一个节点开始与前一个节点进行判断,如果有序就寻找未排序节点的下一个节点,否则就遍历已排序节点来找到合适的位置插入。关键是程序的设计:虽然说分成两部分,但是没必要截断或者开辟新的空间,因为需要遍历两部分List,所以需要一个临时节点pos来遍历有序节点,未排序的节点用cur->next指向。
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if(!head||!head->next) return head;
ListNode *l=new ListNode(0);
l->next=head;
ListNode *cur=head;
while(cur->next)
{
ListNode *tmp=cur->next;
if(tmp->val>=cur->val)
{
cur=cur->next;
continue;
}
ListNode *pos=l;
while(pos->next->val<tmp->val)
pos=pos->next;
cur->next=tmp->next;
tmp->next=pos->next;
pos->next=tmp;
}
return l->next;
}
};
148. Sort List
题意:在nlogn时间内和常量空间大小给一个链表排序。
思路:找到链表的middle节点,然后递归对前半部分和后半部分分别进行归并排序,最后对两个以排好序的链表进行Merge。
知识点1:归并排序的整体思想
知识点2:找到一个链表的中间节点的方法(用快慢指针实现)
知识点3:合并两个已排好序的链表为一个新的有序链表
class Solution {
public:
ListNode* getMid(ListNode *head)
{
ListNode *slow=head,*quick=head;
while(quick->next && quick->next->next)
{
quick=quick->next->next;
slow=slow->next;
}
return slow;
}
ListNode* Merge(ListNode *a,ListNode*b)
{
ListNode l(0);
ListNode *cur=&l;
while(a && b)
{
if(a->val<b->val)
{
cur->next=a;
a=a->next;
}
else
{
cur->next=b;
b=b->next;
}
cur=cur->next;
}
cur->next=a?a:b;
return l.next;
}
ListNode* sortList(ListNode* head) {
if(!head||!head->next) return head;
ListNode *mid=getMid(head);
ListNode *next=mid->next;
mid->next=NULL;
return Merge(sortList(head),sortList(next));
}
};
143. Reorder List
题意:给出一个链表,改变链表的顺序,就是一个头后接一个尾,尾接原来头的下一个,以此类推。
思路:很容易想到按照题目的要求来,就是从第一个头节点直接指到最后一个节点。但是到了最后一个节点的时候就找不回前一个节点,或许遍历链表获取节点数,然后每次都从头开始遍历到需要的节点,明显时间会很长,而且链表已经改变,不能找到。所以采用分割列表和翻转链表的方法。对半分开,将后半段翻转,然后就是合并两个链表。
class Solution {
public:
void reorderList(ListNode* head) {
ListNode *slow=head,*quick=head;
if(!head || !head->next|| !head->next->next) return ;
while(quick->next &&quick->next->next)
{
slow=slow->next;
quick=quick->next->next;
}
ListNode *mid=slow->next;
slow->next=NULL;
ListNode *last=mid;
ListNode *pre=NULL;
while(last)
{
ListNode *next=last->next;
last->next=pre;
pre=last;
last=next;
}
while(head && pre)
{
ListNode *tmp=head->next;
head->next=pre;
pre=pre->next;
head->next->next=tmp;
head=tmp;
}
}
};