24.两两交换链表中的节点
题目链接:https://leetcode.cn/problems/swap-nodes-in-pairs/
文章讲解: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
视频讲解:https://www.bilibili.com/video/BV1YT411g7br
状态:做了出来
思路
自己看到题目的第一想法:
先单独谈论空节点和一个节点的情况,然后就可以讨论循环中连续两个和连续三个的情况
看完随想录之后的想法:
大题思想是一样的,不过这里是从虚拟头节点出发为cur,我自己是把虚拟头节点当成了pre开始出发,二者比较起来的差异就是我自己写的时候,我是从头节点开始跳的,1-3-。。。而代码随想录是从0开始跳的,0-2-4,这样做的好处是本身奇数的时候就不用排最后两个,因此代码更简答
代码实现
①虚拟头节点当pre,从头节点开始跳
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy_head = new ListNode(0);
dummy_head -> next = head;
ListNode* cur = head;
ListNode* pre = dummy_head;
if(head == NULL || head -> next == NULL){
return head;
}else{
ListNode* new_head = head -> next;
while(cur -> next != NULL){
if(cur -> next -> next != NULL){
ListNode* tmp = cur -> next -> next;
cur -> next -> next = cur;
pre -> next = cur -> next;
cur -> next = tmp;
pre = cur;
cur = cur -> next;
}else{
cur -> next -> next = cur;
pre -> next = cur -> next;
cur -> next = NULL;
}
}
return new_head;
}
}
};
②从虚拟头节点开始跳
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* dummy_head = new ListNode(0);
dummy_head -> next = head;
ListNode* cur = dummy_head;
while(cur -> next != NULL && cur -> next -> next != NULL){
ListNode* tmp = cur -> next -> next -> next;;
cur -> next -> next -> next = cur -> next;
cur -> next = cur -> next -> next;
cur -> next -> next -> next = tmp;
cur = cur -> next -> next;
}
return dummy_head -> next;
}
};
今天时间分配不好,补了昨天的,今天的就做出一道,明天再补了
============================================
补
19.删除链表的倒数第N个节点
题目链接:https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
文章讲解:https://programmercarl.com/0019.%E5%88%A0%E9%99%A4%E9%93%BE%E8%A1%A8%E7%9A%84%E5%80%92%E6%95%B0%E7%AC%ACN%E4%B8%AA%E8%8A%82%E7%82%B9.html
视频讲解:https://www.bilibili.com/video/BV1vW4y1U7Gf
状态:用比较笨的方法写了出来
思路
自己看到题目的第一想法:
用之前写过设计链表中查找索引元素的方法,去找到倒数第N+1个元素,然后去删除
看过代码随想录之后的想法:
可以设置两个指针,快指针和慢指针。先让快指针比慢指针先走n步,然后再快慢指针一起走,到最后快指针为空指针时,此时慢指针就是我们要删除的节点,我们删除节点时一般看前一个节点,因此快指针需要先走n+1步。
代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy_head = new ListNode(0);
dummy_head -> next = head;
ListNode* fast = dummy_head;
ListNode* slow = dummy_head;
n++;
while(n --){
fast = fast -> next;
}
while(fast != NULL){
fast = fast -> next;
slow = slow -> next;
}
slow -> next = slow -> next -> next;
return dummy_head -> next;
}
};
面试题02.07.链表相交
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
文章讲解:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html
状态:做了出来
思路
利用上一题删除倒数第N个元素的思想,两个链表若有交叉点,则结尾后一段一定是相等的,因此我们可以让长度长的链表先走,让两个链表末位对齐,然后就是同步走,直至找到节点相等的位置
代码随想录里有个思想可以借鉴,就是为了少一次重复的循环,可以一直让A链表保持最长,若不是最长,则swap(headA,headB)
代码实现
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode* curA = headA;
ListNode* curB = headB;
int lenA = 0, lenB = 0;
while (curA != NULL) { // 求链表A的长度
lenA++;
curA = curA->next;
}
while (curB != NULL) { // 求链表B的长度
lenB++;
curB = curB->next;
}
curA = headA;
curB = headB;
// 让curA为最长链表的头,lenA为其长度
if (lenB > lenA) {
swap (lenA, lenB);
swap (curA, curB);
}
// 求长度差
int gap = lenA - lenB;
// 让curA和curB在同一起点上(末尾位置对齐)
while (gap--) {
curA = curA->next;
}
// 遍历curA 和 curB,遇到相同则直接返回
while (curA != NULL) {
if (curA == curB) {
return curA;
}
curA = curA->next;
curB = curB->next;
}
return NULL;
}
};
环形链表Ⅱ
题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/
文章讲解:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html
视频讲解:https://www.bilibili.com/video/BV1if4y1d7ob
状态:不会
思路
首先,我们考虑如何找到环,当设置一个快指针步长为2,慢指针步长为1,若有环,则它们终会相遇。
如何去找寻入口呢?
可定义slow:x+y,fast:x+y+n(y+z),由于fast是slow速度的二倍,则2(x+y)=x+y+n(y+z)
化简得x=z+(n-1)(y+z),可知x为z+走了n-1圈,因此找入口时,注意一下,一个从起始点出发,一个从相遇点出发,而这一定能够同时到达环形入口处。
我们解答一下为什么一圈就追了
代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast -> next != NULL){
fast = fast -> next -> next;
slow = slow -> next;
if(fast == slow){
ListNode* index1 = fast;
ListNode* index2 = head;
while(index1 != index2){
index1 = index1 -> next;
index2 = index2 -> next;
}
return index1;
}
}
return NULL;
}
};
收获
首先链表里面也经常用双指针,pre和cur指针以及快慢指针,
在间隔跳转的时候,考虑从虚拟头节点还是头节点开始跳
环形相关的知识
链表的总结