【leetcode 19】删除链表的倒数第N个结点
思路
1.定义fast指针和slow指针,初始值为虚拟头结点
2.fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作),如图:
3.fast和slow同时移动,直到fast指向末尾,如题:
4.删除slow指向的下一个节点
快指针走n+1步
代码
伪代码
dummyHead = new Node;
fast = dummyHead;
slow = dummyHead;
n++;
while(n-- && fast !=NULL){
fast = fast ->next;
}
while(fast != NULL){
fast = fast -> next;
slow = slow -> next;
}
slow -> next = slow -> next -> next;
return dummyHead -> next;
代码
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* slow = dummyHead;
ListNode* fast = dummyHead;
while(n-- && fast != NULL) {
fast = fast->next;
}
fast = fast->next; // fast再提前走一步,因为需要让slow指向删除节点的上一个节点
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
// ListNode *tmp = slow->next; C++释放内存的逻辑
// slow->next = tmp->next;
// delete tmp;
return dummyHead->next;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
【leetcode 142】环形链表
判断链表是否有环
原理:可以使用快慢指针法,分别定义 fast 和 slow 指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
解释:fast指针一定先进入环中,如果fast指针和slow指针相遇的话,一定是在环中相遇,这是毋庸置疑的。
通俗易懂:相当于套圈,一定会相遇
如果有环,如何找到这个环的入口
假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z。
速度 fast为2,slow为1
路程 slow=x+y fast=x+y+n(y+z)
时间相等 列等式
意义从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点
也就是在相遇节点处,定义一个指针index1,在头结点处定一个指针index2。 让index1和index2同时移动,每次移动一个节点, 那么他们相遇的地方就是 环形入口的节点。
代码
伪代码
fast = head;
slow = head;
while(fast != NULL && fast ->next != NULL){
fast = fast -> next -> next;
slow = slow -> next;
if(slow == fast){
index1 = fast;
index2 = head;
}
while(index1 != index2){
index1 = index1 -> next;
index2 = index2 -> next;
}
return index1;
}
return NULL;
代码
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {// 有环
ListNode index1 = fast;
ListNode index2 = head;
// 两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
while (index1 != index2) {
index1 = index1.next;
index2 = index2.next;
}
return index1;
}
}
return null;
}
}