链表分割_牛客题霸_牛客网
![![[Pasted image 20241028143227.png]]](https://i-blog.csdnimg.cn/direct/475836f8fdc544a695b73a96a8dd1509.png)
x=3
小于3的尾插到第一条链表,大于等于3的尾插到第二条链表,最后把两个链表连接起来
带哨兵位头节点会更简单,不用考虑哪个链表为空的情况
![![[Pasted image 20241028145351.png]]](https://i-blog.csdnimg.cn/direct/650116ee634d4931bbfb8142dd1b7fe1.png)
直接让ltail的next指向ghead的next
![![[Pasted image 20241028145415.png]]](https://i-blog.csdnimg.cn/direct/0f8ccc5a7c5746c8993bc6d2429f338c.png)
- 若第一个链表为NULL
![![[Pasted image 20241028145504.png]]](https://i-blog.csdnimg.cn/direct/0492932c647c4cb4a98cad32b556d66a.png)
也是ltail的next指向ghead的next
![![[Pasted image 20241028145556.png]]](https://i-blog.csdnimg.cn/direct/35fcae2a31d0452e986d39c80505b6d7.png)
- 有可能出现带环链表
![![[Pasted image 20241028150259.png]]](https://i-blog.csdnimg.cn/direct/c5cd74948b93463783fe49af00490781.png)
所以还需要将gtail的next置空
ListNode* partition(ListNode* pHead, int x) {
struct ListNode* ghead, *gtail, *lhead, *ltail;
ghead = gtail = (struct ListNode*)malloc(sizeof(struct ListNode));
lhead = ltail = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* cur = pHead;
while (cur)
{
if (cur->val < x)
{
ltail->next = cur;
ltail = ltail->next;
}
else
{
gtail->next = cur;
gtail = gtail->next;
}
cur = cur->next;
}
ltail->next = ghead->next;
gtail->next = NULL;
struct ListNode* head = lhead->next;
free(lhead);
free(ghead);
return head;
}
free哨兵位之前需要将头节点保存下来
链表的回文结构_牛客题霸_牛客网
通过快慢指针,找到链表的中间位置,将链表的后半部分逆置,然后两个指针一个从头,另一个从中间开始,挨个比较
- 有奇数个数据
![![[Pasted image 20241028153744.png]]](https://i-blog.csdnimg.cn/direct/f875d789a62d4a6dbb890970cf75e33e.png)
![![[Pasted image 20241028153804.png]]](https://i-blog.csdnimg.cn/direct/76cbad3f127b49eeb7b4733dbc9ace89.png)
![![[Pasted image 20241028153827.png]]](https://i-blog.csdnimg.cn/direct/32ccee192c3f43eaa4872f69cbdf9b7e.png)
虽然后半部分逆置了,但是2的next还是存的3的地址
2可以不置空
- 偶数个数据
![![[Pasted image 20241028153940.png]]](https://i-blog.csdnimg.cn/direct/04918c134e6f4d66a663c3f6e927d2f9.png)
![![[Pasted image 20241028153950.png]]](https://i-blog.csdnimg.cn/direct/6415ea42e29945258aaa5b42a0ed1d3f.png)
![![[Pasted image 20241028154006.png]]](https://i-blog.csdnimg.cn/direct/f199c155461641ce921c773b0cc328a9.png)
//找到中间节点
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* slow = head, *fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
//逆置
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur = head;
struct ListNode* newhead = NULL;
while (cur)
{
struct ListNode* next = cur->next;
cur->next = newhead;
newhead = cur;
cur = next;
}
return newhead;
}
//判断回文
bool chkPalindrome(ListNode* A) {
struct ListNode* mid = middleNode(A);
struct ListNode* rmid = reverseList(mid);
while (rmid && A)
{
if (rmid->val != A->val)
{
return false;
}
rmid = rmid->next;
A = A->next;
}
return true;
}
160. 相交链表
判断尾节点的地址是否相同,来判断是否相交
尾节点相等就相交,不相等就不相交
找交点,用一个链表的值,去另外一个链表找一遍,比的是地址
第一个相等的就是交点
![![[Pasted image 20241028205756.png]]](https://i-blog.csdnimg.cn/direct/5385b852298f4b6798513c4f9bfa57e5.png)
时间复杂度是 O ( n 2 ) O(n^{2}) O(n2)
- 计算出两个A,B的长度,记为lenA,lenB
- 长的链表先走差距步abs(lenA-lenB)
- 不一样长的是前半段,走完差距步后,可以认为后半段是一样长的
一样长的话,之后依次比对就可以了,不需要逐个比对
如果不相等往后走,第一个相等的就是交点
![![[Pasted image 20241028205826.png]]](https://i-blog.csdnimg.cn/direct/e43f2a685bbd4fcb8f91086b28b15232.png)
时间复杂度是 O ( N ) O(N) O(N)
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA = headA, *curB = headB;
int lenA = 1, lenB = 1;
while (curA->next)
{
curA = curA->next;
++lenA;
}
while (curB->next)
{
curB = curB->next;
++lenB;
}
//尾节点不相等,不相交
if (curA != curB)
{
return NULL;
}
int gap = abs(lenA - lenB);
struct ListNode* longList = headA, *shortList = headB;
if (lenA < lenB)
{
longList = headB;
shortList = headA;
}
//长的先走差距步
while (gap--)
{
longList = longList->next;
}
//同时走,找交点
while (longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return longList;
}
141. 环形链表
![![[Pasted image 20241028212352.png]]](https://i-blog.csdnimg.cn/direct/83d9da8745a24e239834562f883ca76a.png)
入环节点可以是任意一个节点,可以是头节点,中间节点或尾节点
如何判断是否链表带环
用两个指针,
![![[Pasted image 20241028212748.png]]](https://i-blog.csdnimg.cn/direct/8faf2fa7b094498aa94f0190ee3f2bd8.png)
slow一次走一步,fast一次走两步
![![[Pasted image 20241028212949.png]]](https://i-blog.csdnimg.cn/direct/a040b9011c8c43b5abf5f748cb6820da.png)
slow到中间位置,fast刚好进环
![![[Pasted image 20241028213053.png]]](https://i-blog.csdnimg.cn/direct/169c40888a3a4b97859ecf6fabb643a0.png)
slow刚进环,此时两个指针都进环了
两个指针一个快,一个慢,开始追击
![![[Pasted image 20241028213258.png]]](https://i-blog.csdnimg.cn/direct/fbe8fa21f85b4e7981d30434c5d9e2a0.png)
当两个指针相遇,就代表有环
bool hasCycle(struct ListNode *head) {
struct ListNode* slow = head, * fast = head;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (slow == fast)
{
return true;
}
}
return false;
}
一定可以追上
![![[Pasted image 20241028223554.png]]](https://i-blog.csdnimg.cn/direct/2c9f6e1b79fc4ca29ef5aa5f02f69f1e.png)
slow刚到交点时,slow和fast的距离是N
![![[Pasted image 20241028223621.png]]](https://i-blog.csdnimg.cn/direct/09eff41133b940cebea5f5ccf7275751.png)
追击一次以后,之间的距离-1
当slow进环以后,fast开始追击slow,假设slow入环时,之间的距离是N
每追击一次,他们之间的距离缩小1
距离的变化:
N,N-1,N-2,…,2,1,0
当距离为0时,代表相遇
142. 环形链表 II
求环的入口点
思路1
假设起点到入口点长度是L
假设环的周长是C
假设从入口点到相遇点的距离是x
fast走的路程是slow的距离的二倍
![![[Pasted image 20241028230803.png]]](https://i-blog.csdnimg.cn/direct/cfe470cefd9b4040a1d2af43e8ca2f52.png)
slow走的距离:L+x
x的距离一定小于C,因为如果x大于C,fast走的距离一定大于2C,早就追上了
![![[Pasted image 20241028232019.png]]](https://i-blog.csdnimg.cn/direct/a82977538c3b4a32bfb27b70cec0afac.png)
slow进环后一圈内,fast一定追上slow
slow进环时,假设fast在环里走了n圈
如果不足n圈,追的时候会补足n圈然后加上x
fast走的距离:L+n*C+x
2
(
L
+
x
)
=
L
+
n
⋅
C
+
x
2(L+x)=L+n\cdot C+x
2(L+x)=L+n⋅C+x
L
=
n
⋅
C
−
x
L=n\cdot C-x
L=n⋅C−x
一个指针从起点开始走,一个指针从相遇点走,会在入口点相遇
![![[Pasted image 20241029092657.png]]](https://i-blog.csdnimg.cn/direct/773b1fdddcdf4315b3abd01f2ff54ee6.png)
一个指针从相遇点走,走了(N-1)圈,之后走了(C-x)
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow, *fast;
slow = fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
struct ListNode* meet = slow;
while (head != meet)
{
head = head->next;
meet = meet->next;
}
return meet;
}
}
return NULL;
}
思路2
找到相遇点之后
将环从相遇点断开
![![[Pasted image 20241029094012.png]]](https://i-blog.csdnimg.cn/direct/165cfccca21643b495224e5fac5bdb9f.png)
将newhead指针指向相遇点的下一个节点,然后断开newhead和meet指针指向的节点
newhead = meet->next;
meet->next = NULL;
这个时候求入口点就相当于求相交链表的交点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode* curA = headA, *curB = headB;
int lenA = 1, lenB = 1;
while (curA->next)
{
curA = curA->next;
++lenA;
}
while (curB->next)
{
curB = curB->next;
++lenB;
}
//尾节点不相等,不相交
if (curA != curB)
{
return NULL;
}
int gap = abs(lenA - lenB);
struct ListNode* longList = headA, *shortList = headB;
if (lenA < lenB)
{
longList = headB;
shortList = headA;
}
//长的先走差距步
while (gap--)
{
longList = longList->next;
}
//同时走,找交点
while (longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return longList;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow, *fast;
slow = fast = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast)
{
struct ListNode* meet = slow;
struct ListNode* newhead = meet->next;
meet->next = NULL;
return getIntersectionNode(newhead, head);
}
}
return NULL;
}
138. 随机链表的复制
单链表+随机指针
不可以拿值来比对,链表中可以有相同的值
![[Pasted image 20241029100306.png]]
找对应的random一定要找相对位置
思路1
暴力求解的时间复杂度 O ( N 2 ) O(N^{2}) O(N2)
- 复制链表
- 算random在原链表的相对位置,控制复制链表
思路2
- 将拷贝节点插入到原节点的后面
![![[Pasted image 20241029101715.png]]](https://i-blog.csdnimg.cn/direct/38a9c91767a64250abe8a7b204db105f.png)
每个拷贝节点都在原节点的后面
2. 置每个拷贝节点的random指针
7的random指向NULL
7的next的节点也指向空
13的random指向7
13的next的节点指向7的next的节点
…
copy->random = cur->random->next
![![[Pasted image 20241029102827.png]]](https://i-blog.csdnimg.cn/direct/552146e16a2e4f31a2c1beb71e225ce2.png)
- 拷贝节点解下来,尾插到一起,回复原链表
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
while (cur)
{
struct Node* next = cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
// 插入
cur->next = copy;
copy->next = next;
// 往后走
cur = next;
}
cur = head;
while (cur)
{
struct Node* copy = cur->next;
// 置copy的random
if (cur->random == NULL)
copy->random = NULL;
else
copy->random = cur->random->next;
cur = copy->next;
}
cur = head;
struct Node* copyhead = NULL, *copytail = NULL;
while (cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
// copy节点尾插到新链表
if (copytail == NULL)
{
copyhead = copytail = copy;
}
else
{
copytail->next = copy;
copytail = copytail->next;
}
// 恢复原链表
cur->next = next;
cur = next;
}
return copyhead;
}
1840

被折叠的 条评论
为什么被折叠?



