LeetCode.19 删除链表的倒数第N个结点
题目
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
思路
删除一个结点,很容易想到找到这个结点的前一个结点pre,让pre的next指向目标结点的next,那么怎样找到这个倒数第n个的pre呢,我们可以借用滑动窗口的思想,维护left和right两个指针,让left和right相差n-1个,那么就可以找到pre,就是我们的left。不明白的可以画一下试试。但是我们可能会遇到一些特殊情况,比如要删除的可能刚好是头节点,比如示例2和示例3,在维护这个n-1距离时,就已经到了链表尾部,这个时候我们可以直接返回头节点的next即可,其他情况就直接维护这个窗口使得right到达尾部,再来进行删除。切记不要忘记判断节点是否为空。否则会出错。
上代码:
/**
* 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* res=head;
ListNode* left=res;
ListNode* right=res;
while(n--){
right = right->next;
}
if (right == nullptr) {//要删除的是头节点
ListNode* temp = res;
res = res->next;
delete temp;
return res;
}
while(right != nullptr&&right->next!=nullptr){
left=left->next;
right=right->next;
}
ListNode* temp = left->next;
if (temp != nullptr) {
left->next = temp->next;
delete temp;
}
return res;
}
};
感想
链表是真难啊,也是真烦啊。这个题稍微一想就能想出来,当然,投机取巧的还有一种办法,搞个vector<ListNode*>用这个来模拟删除,但是时间复杂度会翻倍,并且也不是这题的目的所在,实在没办法了可以这样做,像链表反转啊,k个一组链表反转都可以这样投机取巧,但是这不是题目用链表的意义,我们还是要考虑回归它的本意。想起前几天我实在写不出来反转用的就是这样的方法,我未来男朋友用5S和10S做例子告诉我虽然是常数级翻倍,在数据量很大的情况下差距也会很大,不要想着投机取巧。大家也要改变思想,我们一起加油。(放个题外话,今天和未来男朋友成功组了王者荣耀cp,他送了我好多玫瑰道具,一下干6级去了。)