标题每日一题-15-删除链表的倒数第 N 个结点
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
进阶:你能示例 1:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jk8AZUn0-1621146305427)(https://assets.leetcode.com/uploads/2020/10/03/remove_ex1.jpg)]
输入: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
尝试使用一趟扫描实现吗?
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) {
if(head->next == nullptr) return {};
int sum = 0;
ListNode * index = head;
while(index!= nullptr){
index = index->next;
sum++;
}
int idex = sum - n + 1;
if(idex == 1){
head = head -> next;
return head;
}
ListNode* p = head;
sum = 1;
while(sum < idex-1){
p = p -> next;
sum++;
}
p->next = p->next->next;
return head;
}
};
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) {
stack<ListNode*> st;
ListNode* p = head;
while(p){
st.push(p);
p = p->next;
}
if(n == st.size()){
head = head->next;
return head;
}
while(n--){
st.pop();
}
st.top()->next = st.top()->next->next;
return head;
}
};
3.使用双指针的方法实现,设置两个指针,第一个指针和第二个指针之间相差n个元素,这样通过向后移动,当第二指针指向链表的尾部的时候,第一个指针刚刚好指向链表的倒数第n个元素
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode(0, head);
ListNode* first = head;
ListNode* second = dummy;
for (int i = 0; i < n; ++i) {
first = first->next;
}
while (first) {
first = first->next;
second = second->next;
}
second->next = second->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
};
PS:我们在实现删除节点的操作时候,可以引入一个人哑节点插入到链表的头部,然后就可以实现对首节点进行删除操作,不需要进行单独的判断操作。