链表=双指针=空间鲁棒性
快指针先走n步,当快指针走到null时,慢指针指向倒数第n个。因为遍历一遍,所以用一个int变量记录快指针走了几步,当快指针走的步数大于等于n时,才让慢指针开始走。因为要删除,所以要来一个pre指针记录当前指针的前驱指针,删除操作就是直接让pre指向当前指针的next即可。最后判断,如果快指针在走n步直接走到结尾了,那么证明要删除头结点,直接返回head->next即可,通过判断pre是否为空来看是否是删除头。否则就删除slow指针指向的结点,最后返回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* removeNthFromEnd(ListNode* head, int n) {
//给定n有效,就不用判断链表长度什么的了
//链表=双指针=空间鲁棒性
//先通过双指针找到第n个结点,然后将它的前后相连即可,快指针先走n步,慢指针才开始走,快走到尾了,慢就是第n个,在走的过程要时刻时刻记录当前指针的前一个指针方便删除当前指针,当快是null时,慢就是倒数第n个
if(head == nullptr || head->next == nullptr) return nullptr;
ListNode* pre = nullptr;
//head可能要变,因为可能删除的就是头
ListNode* slow = head, *fast = head;
int xianzou = 0;
while(fast != nullptr){
if(xianzou >= n){
pre = slow;
slow = slow->next;
}
fast = fast->next;
xianzou++;
}
//如果前驱指针没有改变,证明在快指针先走n步的时候直接走到链表尾了,证明要删除的就是头结点
if(pre == nullptr) return head->next;
pre->next = slow->next;
return head;
}
};
二刷,记得把pre设为nullptr,最后判断,如果pre没被改过,等于删除head结点,直接返回head->next即可
/**
* 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) {
//删除倒数第N个结点,长度>=n
if(head == nullptr) return nullptr;
//链表=空间鲁棒性=双指针,快慢指针,一个先走n步,当快指针到null时,慢指针刚好是倒数第n个,每一轮都要记录前驱指针,不然到倒数第n个的时候不知道怎么把前后相连了
//一个结点也是特殊情况
ListNode* h = new ListNode(0);
h->next = head;
ListNode* slow = head, *fast = head;
//pre初始值不能直接等于head,不然要删除头结点还是要删除第二个结点,pre指向的都是头,所以一开始设为空
ListNode* pre = nullptr;
//一边扫描简单,只要在fast走n步之前,slow一步都不走就行了
int fastBu = 0;
while(fast != nullptr){
if(fastBu++ >= n){
pre = slow;
slow = slow->next;
}
fast = fast->next;
}
//如果pre没有动过,就删除头结点,返回头结点的下一个结点即可
if(pre == nullptr) return head->next;
pre->next = slow->next;
return h->next;
}
};
记得最后要判断pre是否为空,如果为空,证明slow一步都没走,直接删除头结点就行了
/**
* 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) {
//双指针+尺取,让快的先走n步,然后同时走,当快的到nullptr了,慢的就是倒数第n个
//一趟扫描,时刻判断是否越界
//还是三指针,pre,cur,不需要next,因为cur直接指向next就行了当fast为空时让pre指向next
ListNode* pre, *cur = head, *fast = head;
while(fast != nullptr){
fast = fast->next;
//要注意是n<=0时slow指针才可以开始走
if(n--<=0){
pre = cur;
cur = cur->next;
}
}
//要先考虑要删去的是不是第一个结点,如果是第一个结点的话,直接用一个空的pre去操作next会出错
if(pre == nullptr) return head->next;
//此时要判断n是否小于等于0,如果小于等于0,证明结点个数大于等于n
pre->next = cur->next;
return head;
}
};