代码随想录-017-LeetCode19.删除链表的倒数第N个节点

目录

  • 前言
    • 题目
    • 1. 删除倒数链表(快慢指针法)
      • 思路(定义变量)
    • 2. 本题思路分析:
    • 3. 算法实现
    • 4. 算法分析
    • 5. 算法坑点

前言

“代码随想录”刷题记录。总结笔记均会放在“算法刷题-代码随想录”该专栏下,以下为原文的链接。
代码随想录此题链接

题目

给你一个链表,删除链表的倒数第 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

进阶:你能尝试使用一趟扫描实现吗?

1. 删除倒数链表(快慢指针法)

思路(定义变量)

  1. 定义链表结构的结构体struct
  2. 虚拟头节点 dummy。(一看到跟链表删除相关的第一反应就是设置虚拟头节点,为了应对删除实体头节点的特殊情况,可看文章最后的算法坑点部分)
  3. 三个struct类型的指针,分别是fast,slow。

2. 本题思路分析:

前言

  • 链表删除,指针应该指向要删除节点的前一个节点的位置(所以需要设置虚拟头节点来应对实体头节点的删除问题),所以要删除倒数第n个节点,必须让指针到达倒数第n+1个的节点位置上。
  • 而要在一趟扫描完,就是借助双指针,让一个指针在到达最后一个元素的同时,让另外一个元素正好到达倒数第n+1个节点上,也就是说这两个指针节点相差n个节点,
  • 也就是起始两个都在虚拟头节点上的指针,需要让一个节点先走n个节点,然后两个节点开始一起移动,当先走的指针到达最后一个节点的位置上时,这时后出发的指针就正好指向了倒数第n+1个节点上。
  • 这个时候就可以删除倒数第n个节点了。
  1. fast,slow全部指向dummy虚拟头节点。
  2. 将dummy的next指向head(易错点,特别容易遗忘)
  3. fast指针先移动n个位置(n是要删除元素倒数的第n个的位置),然后fast、slow全部后移,直到fast挪到最后一个元素位置上(fast -> next != nullptr)。
  4. 此时slow就在要删除节点的前一个节点上了,然后删除slow的下一个节点
  5. 然后记得要将dummy的next指向head(易错点,容易漏),然后再将dummy删除。

3. 算法实现

  • 代码:
#include
#include
using namespace std;
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){}
};
//快慢指针法 
ListNode* removeNthFromEnd(ListNode* head, int n) {
		//一般涉及到删除节点,首先考虑使用到  虚拟头节点
		ListNode* dummy = new ListNode(0); 
		dummy -> next= head;//易错点,创建虚拟节点dummy后,老是漏掉把head放在它的next上(不要弄反或者忘记写了)
		ListNode* fast = dummy;
		ListNode* slow = dummy;
		while(n--){
			fast = fast -> next;
		}
		while(fast -> next != nullptr){
			fast = fast -> next;
			slow = slow -> next;
		}
		//现在slow在待删除节点的前一个位置 
		//删除节点 
		ListNode* tmp = slow -> next;
		slow -> next = slow -> next -> next;
		delete tmp;
		//易错点:老是漏掉这步,将head放在dummy的next,删除dummy节点
		head = dummy -> next;
		delete dummy; 
		return head;
} 

4. 算法分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

5. 算法坑点

  1. 为什么要设置dummy虚拟头节点?
    因为若没有设置虚拟头节点,那么代码对于只有一个实际的头节点的情况需要特殊处理。
    所以为了代码简化,要加上虚拟头节点。
  2. dummy初始化后,记得将dummy->next指向head。
  3. 删除指定元素后,记得在返回head前,将dummy->next赋值给head,并将dummy删除。

你可能感兴趣的:(算法刷题-代码随想录,链表,数据结构)