之前写408套卷的时候就遇到过这类题目,现在写力扣又遇到了,确实挺有意思的一个算法,就来跟大家分享分享。
转自力扣
删除链表的倒数第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
进阶:你能尝试使用一趟扫描实现吗?
我希望大家看完这篇文章后,都能实现用一趟扫描就能完成!首先,看到这道题的第一思路:
方法一,把链表复制到数组中,再对数组进行操作,同时把数据复制到一个新链表上;
方法二,扫描两次,第一次获取链表长度,第二次对链表进行操作,删除倒数第N个结点;
无论是方法一还是方法二,都不可避免进行了两趟扫描,那我们有没有一种更加高效的算法,只需一趟扫描就能完成呢?答案是肯定的!以示例1为例,如图所示:
相信以大家的聪明才智,看完这几个图应该就明白什么意思了(我坚信.jpg)!最后,还有一个很巧妙的点——在链头加个空的头节点,这样方便操作(例如,当链表长度为2时,要删除倒数第二个结点)。
AC代码:
/**
* 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* l_head = new ListNode;
l_head->next = head;
ListNode *p, *q;
p = l_head;
q = l_head;
for(int i=1; i<=n; i++)//此时p、q已经间隔n位
{
q = q->next;
}
while(q->next!=nullptr)
{
p = p->next;
q = q->next;
}
p->next = p->next->next;
return l_head->next;
}
};
看懂之后,就来尝试一下考研真题吧(2009年408数据结构算法题)
其实,也没那么难对吧!感兴趣的同学可以代码实现一下,在考研的同学就需要手写代码了,看看是不是可以拿满分了?