今天还是更新两个关于链表的题
第一个
题目描述:
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
思路:
1.这个题的总体思路就是定义两个带哨兵位的链表,比x大的放到一个链表中,比x小的放到一个链表中,也就是将原链表分割给这两个新定义得到的链表,最后合起来。
2.这种题其实还有一个规律,其实这个题使用尾插来做就是最简单的,而尾插往往就需要定义哨兵位来解决,这样的话比较简单,关于这个问题,其实我之前写过一篇返回倒数第k节点的文章,里面如果定义了哨兵位的话,可以省去不少的麻烦,比如判空
合并两个有序链表(leetcode简单)+链表中倒数第k个结点_何以过春秋的博客-CSDN博客
3.这里就是一步步尾插,但要注意有极端情况的发生,就是可能形成环,比如给链表 3 4 5 7 1 2,给x为6,那么最后输出应该是3 4 5 1 2 7 ,这里问题就来了,7的next其实还是指向1,那么这里就会形成环,所以必须对它进行置空
4.最后只要将哨兵位释放掉就行,释放前记得保存头节点,以免找不到。
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
//定义两个哨兵位的头节点
struct ListNode*greaterhead,*greatertail,*lesshead,*lesstail;
greaterhead=greatertail=(struct ListNode *)malloc(sizeof(struct ListNode));
lesshead=lesstail=(struct ListNode *)malloc(sizeof(struct ListNode));
//置空
greatertail->next=NULL;
lesstail->next=NULL;
struct ListNode*cur=pHead;
while(cur)
{
if(cur->val<x)
{
lesstail->next=cur;
lesstail=lesstail->next;
}
else
{
greatertail->next=cur;
greatertail=greatertail->next;
}
cur=cur->next;
}
lesstail->next=greaterhead->next;
//这里考虑极端情况,否则可能形成环
greatertail->next=NULL;
//将两个哨兵位的头节点释放掉,但要提前定义一个节点,也就是哨兵位的next,最后做返回用。
struct ListNode*head=lesshead->next;
free(greaterhead);
free(lesshead);
return head;
}
};
第二个
思路:其实这个题以前经常考
1.这个题首先必须想明白,不能遍历整个链表!
2.使用快慢指针来做,这里其实还有一个非常经典的面试问题,那就是如果有环,为什么fast和slow一定能碰上?
证明:假设slow入环时,fast和slow的距离已经差了N步,接下来两者走一次,相差N-1步,接下来两者走一次,相差N-2步,也就他们之间的距离每次缩小1,走N步,距离变为零,也就是相遇了。
再想想,如果fast一次走3步,走4步呢?是不是还一定能追上?’
不一定了,道理同上。
bool hasCycle(struct ListNode *head) {
struct ListNode*fast=head;
struct ListNode*slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return true;
}
return false;
}