今天要把代码随想录中的链表部分刷完,开冲!!!
今日任务:
- 删除链表的倒数第N个节点
- 链表相交
- 环形链表ii
一:19.删除链表的倒数第N个节点
Leetcode题目:【19.删除链表的倒数第N个节点】
这个题目就是需要转化下,倒数第N个元素可以转化为正数第size - N + 1个元素。
需要考虑的问题是:
(1)如何由正数第几个元素 ——》 倒数第几个元素
(2)如何偏移到要删除的元素那里。
/**
* 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) {
int size = 0;
ListNode *dummyNode = new ListNode(0);
dummyNode -> next = head;
ListNode *cur = dummyNode;
while(cur -> next != NULL){
size++;
cur = cur-> next;
}
cur = dummyNode;
// 倒数第2个代表就是正数size - n + 1
for(int i = 1; i<size - n + 1; i++){
cur = cur -> next;
}
ListNode * tmp = cur -> next;
cur -> next = cur -> next -> next;
delete tmp;
return dummyNode -> next;
}
};
二、面试题02.07.链表相交(思想很重要)
Leetcode题目:【面试题02.07.链表相交】
这个题目一上来确实没啥思路,感觉是两个链表需要上个指针进行偏移。
需要注意的点:
(1)两个链表的交点注意不是数值相等,而是指针相等;
(2)两个链表如果相交,那后面一定是一样的,所以它的思路就是先计算数量,然后偏移到短的那个的共同位置;
(3)后买你如果curA和curB是否相同,如果相同那就是叫交点,否则循环退出返回空指针。
思路描述
这个题目中非常重要的点:
(1)为了减少代码,需要保证A链表的长度必须大于B链表的长度,如果小于,那么就需要交换两者;
(2)curA提前走的索引的步数一定要算清楚。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode *dummyNodeA = new ListNode(0);
ListNode *dummyNodeB = new ListNode(0);
ListNode *curA = dummyNodeA;
ListNode *curB = dummyNodeB;
dummyNodeA -> next = headA;
dummyNodeB -> next = headB;
int length_A = 0, length_B = 0;
while(curA -> next != NULL){
length_A++;
curA = curA -> next;
}
while(curB -> next != NULL){
length_B++;
curB = curB -> next;
}
// 保证curA始终是长的,curB始终是短的
if(length_A < length_B){
swap(length_A, length_B);
swap(dummyNodeA, dummyNodeB);
}
curA = dummyNodeA;
curB = dummyNodeB;
int gap = length_A - length_B;
for(int i = 0; i<gap; i++) curA = curA -> next;
while(curA != NULL){
if(curA == curB){
return curA ;
}
curA = curA -> next;
curB = curB -> next;
}
return NULL;
}
};
三、142.环形链表II
Leetcode题目:【142.环形链表II】
这个题非常有印象,而且最后求进入点好像还有个公式,但是现在有点忘记了,所以需要看一下才能回忆起来。
解决问题主要有两点:
(1)如何判断有环?
(2)环的入口在哪里?
- 如何判断有环
- 定义两个指针,一个快指针(每次走两步),一个慢指针(每次走一步),只要两者能相遇,那就是有环,因为按照常识,如果有环的话,指针是1个单位长度依次去追,一定可以追上.
- 如何确定环的入口:
结论:从头节点出发一个指针,从相遇节点出发,这两个指针每次都只走一个几点,那么当这两个指针相遇的时候就是环形入口的节点。
写代码时需要注意的点:
(1)终止条件:fast和fast->next均不为空才可实现,原因是需要考虑链表为空或者只有一个元素的情况;
(2)判断是否成环的时候,应该先走,然后在判断,这是因为刚开始fast和slow指针都指向head,因为直接就进循环了;
(3)当判断成环之后,如何利用结论求解入环位置是直接利用结论:一个从头节点head,另一个从相遇点,然后第一次相遇的点就是环的入点。
/**
* 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* fastpoint = head;
ListNode* slowpoint = head;
while(fastpoint != NULL && fastpoint -> next!= NULL){
fastpoint = fastpoint -> next -> next;
slowpoint = slowpoint -> next;
if(fastpoint == slowpoint){
cout << "The link is true circle link" << endl;
fastpoint = head;
while(fastpoint != slowpoint){
fastpoint = fastpoint -> next;
slowpoint = slowpoint -> next;
}
return fastpoint;
}
}
return NULL;
}
};
四、总结:
链表主要还是看操作的数量程度,其中翻转链表、链表相交和环形链表注意求解的思想。