今日学习的文章链接,或者视频链接
24. 两两交换链表中的节点
用虚拟头结点,这样会方便很多。
本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点。
题目链接/文章讲解/视频讲解: https://programmercarl.com/0024.%E4%B8%A4%E4%B8%A4%E4%BA%A4%E6%8D%A2%E9%93%BE%E8%A1%A8%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
19.删除链表的倒数第N个节点
双指针的操作,要注意,删除第N个节点,那么我们当前遍历的指针一定要指向 第N个节点的前一个节点,建议先看视频。
面试题 02.07. 链表相交
本题没有视频讲解,大家注意 数值相同,不代表指针相同。
142.环形链表II
算是链表比较有难度的题目,需要多花点时间理解 确定环和找环入口,建议先看视频。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
自己看到题目的第一想法
- 两两交换链表中的节点
自己思考的是对的,但是没能用代码描述,画图后好多了
- 删除链表的倒数第 N 个节点
快慢指针的简单应用,快指针先走 n 步,之后慢指针和快指针一起走,当快指针为 NULL
时,慢指针到了应该删除的节点的前一个节点
- 链表相交
没什么思路
- 环型链表
只记得判断环是否存在,判断入口忘记了
看完代码随想录之后的想法
- 两两交换链表中的节点
- 链表相交
获取两条链表的长度,长度差为 gap
,长的链表先 gap 步,之后两个链表同时走,相同即相遇
- 环型链表
快慢指针,相遇即有环
头节点长度与相遇节点到环入口距离相等
题解:
#include "linkList.h"
#include <unistd.h>
/* 两两交换链表中的节点 */
// dummyHead 1 2 3 4 5 6
// 2 1 4 3 6 5
listNode *swapPairs(linkList *pList){
if (0 == pList->len){
return NULL;
}
listNode *dummyHead = pList->pHead; // 该节点可以理解为虚拟头节点,指向真正的头节点
listNode *pCurNode = dummyHead;
// 奇数个和偶数个元素不同处理,两个条件的顺序反了的话可能空指针异常
while (pCurNode->next && pCurNode->next->next){
listNode *pTmpNode1 = pCurNode->next;
pCurNode->next = pTmpNode1->next; // 步骤1
listNode *pTmpNode2 = pCurNode->next->next; // 保存
pCurNode->next->next = pTmpNode1; // 步骤二
pTmpNode1->next = pTmpNode2; // 步骤三
pCurNode = pCurNode->next->next; // 往后移动两个
}
return dummyHead->next;
}
/* 19.删除链表的倒数第N个节点 */
int removeNthFromEnd(linkList *pList, int n){
if (n <= 0 || n>pList->len){
return 0;
}
// 快慢指针都放在虚拟头节点
listNode *pSlowNode = pList->pHead;
listNode *pFastNode = pList->pHead;
// 使得最后指向要删除节点的前一个
n+=1;
// 快指针先走n步
while (n--){
pFastNode = pFastNode->next;
}
// 快慢指针一起移动
while (pFastNode){
pFastNode = pFastNode->next;
pSlowNode = pSlowNode->next;
}
// 删除节点
listNode *pTmpNode = pSlowNode->next;
pSlowNode->next = pSlowNode->next->next;
free(pTmpNode);
return 0;
}
/* 链表相交 */
listNode *getIntersectionNode(linkList *listA, linkList *listB){
int lenA = listA->len;
int lenB = listB->len;
int gap = 0;
listNode *nodeA = listA->pHead->next;
listNode *nodeB = listB->pHead->next;
// 将更长的链表移动gap步
if (lenA>lenB){
gap = lenA - lenB;
while (gap--){
nodeA = nodeA->next;
}
}else{
gap = lenB - lenA;
while (gap--){
nodeB = nodeB->next;
}
}
// 两条链表一起移动
while (nodeA){
if (nodeA == nodeB){
return nodeA;
}
nodeA = nodeA->next;
nodeB = nodeB->next;
}
return NULL;
}
/* 环形链表 */
listNode *detectCycle(linkList *pList) {
// slow和fast均指向头节点
listNode *pSlowNode = pList->pHead->next;
listNode *pFastNode = pList->pHead->next;
while (pFastNode->next && pFastNode->next->next){
pSlowNode = pSlowNode->next;
pFastNode = pFastNode->next->next;
// 快慢指针相遇一定有环且相遇处在环内
if (pFastNode == pSlowNode){
listNode *pTmpNode1 = pList->pHead->next;
listNode *pTmpNode2 = pFastNode;
// 根据公式计算,x = z,即头节点和相遇节点出发,一步一步走相遇处即是环的起点
while (pTmpNode1 != pTmpNode2){
pTmpNode1 = pTmpNode1->next;
pTmpNode2 = pTmpNode2->next;
}
return pTmpNode1;
}
}
return NULL;
}
int main(int argc, char const *argv[])
{
linkList *pList = createList();
insertTailLinkList(pList, 1);
insertTailLinkList(pList, 2);
insertTailLinkList(pList, 3);
insertTailLinkList(pList, 4);
insertTailLinkList(pList, 5);
insertTailLinkList(pList, 6);
showLinkList(pList);
removeNthFromEnd(pList, 0);
showLinkList(pList);
return 0;
}