LeetCode 热题 100_删除链表的倒数第 N 个结点(29_19_中等_C++)(单链表;双指针)(new_delete)

LeetCode 热题 100_删除链表的倒数第 N 个结点(29_19)

题目描述:

给你一个链表,删除链表的倒数第 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、先求出链表的长度,再定位其前驱结点将对应结点删除 。(注意头结点的删除和其他结点不同,因没有前驱结点。)

2、复杂度分析:

① 时间复杂度:O(L),其中 L 是链表的长度。

② 空间复杂度:O(1)。

思路二(双指针):

1、使用两个指针,控制距离为n+1。当后边的指针遍历到NULL时,前边的指针正好指向要删除结点的前驱。(为了统一各个结点的删除操作,这里我们对链表添加一个新头结点(dummyHead),体会和方法一中的不同)。

2、具体思路如下:

① 添加一个新头结点(dummyHead)。

② 先将一个指针tail从链表头结点(dummyHead)开始移动n+1步。再令结点pre指向头节点(dummyHead)。

③ 这时tail和pre同时移动,当tail到达尾结点时,pre正好是倒数第 n 个结点的前去结点。

3、复杂度分析

① 时间复杂度:O(L),其中 L 是链表的长度。

② 空间复杂度:O(1)。

代码实现

代码实现(思路一(计算链表长度)):
cpp 复制代码
ListNode* removeNthFromEnd1(ListNode* head, int n) {
	ListNode *p=head;
	int len=0;
	//统计链表长度 
	while(p!=nullptr){
		++len;
		p=p->next;
	}
	//删除结点为头结点的情况 
	if(len==n){
		p=head;
		head=head->next;
		delete p;
		return head;
	}
	//删除结点不是头结点的情况,先找到前驱结点
	p=head;
	for(int i=1;i<=len-n-1;++i){
		p=p->next;	
	}
	//删除结点 
	ListNode *tmp=p->next;
	p->next=p->next->next;
	//注意将结点释放
	delete tmp;
    return head;
}
代码实现(思路二(双指针)):
cpp 复制代码
ListNode* removeNthFromEnd2(ListNode* head, int n) {
	//为了方便统一删除操作,这里我们对链表添加一个新头结点(dummyHead)
	ListNode *dummyHead=new ListNode(0,head); 
	//pre记录删除结点的前驱结点,tail用于控制距离 
	ListNode *pre=dummyHead,*tail=dummyHead;
	//tail拉开n+1的距离 
	while(n+1){
		tail=tail->next;
		--n;
	} 
	//tail和pre保持n+1个距离移动 
	while(tail!=nullptr){
		tail=tail->next;
		pre=pre->next;
	}
	//删除结点(用tail来存储需删除的结点节省内存空间) 
	tail=pre->next;
	pre->next=pre->next->next;
	head=dummyHead->next;
	delete dummyHead;
	//注意返回头节点之后的结点 
	return head;
}
以思路二为例进行调试:
cpp 复制代码
#include<iostream> 
#include<vector>
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 *createList(vector<int> arr){
	ListNode *head=nullptr,*tail=nullptr;
	for(const auto &val:arr){
		if(head==nullptr){
			tail=head=new ListNode(val);
		}else{
			tail->next=new ListNode(val);
			tail=tail->next;
		}
	}
	return head;
}

//方法二
ListNode* removeNthFromEnd2(ListNode* head, int n) {
	//为了方便统一删除操作,这里我们对链表添加一个新头结点(dummyHead)
	ListNode *dummyHead=new ListNode(0,head); 
	//pre记录删除结点的前驱结点,tail用于控制距离 
	ListNode *pre=dummyHead,*tail=dummyHead;
	//tail拉开n+1的距离 
	while(n+1){
		tail=tail->next;
		--n;
	} 
	//tail和pre保持n+1个距离移动 
	while(tail!=nullptr){
		tail=tail->next;
		pre=pre->next;
	}
	//删除结点(用tail来存储需删除的结点节省内存空间) 
	tail=pre->next;
	pre->next=pre->next->next;
	head=dummyHead->next;
	delete dummyHead;
	//注意返回头节点之后的结点 
	return head;
}

int main(){
	vector<int> a={1,2,3,4,5};
	int n=2;
	//创建单链表
	ListNode *head=createList(a);
	//删除链表的倒数第 N 个结点
	ListNode *ans=removeNthFromEnd2(head,n);
	//输出删除后的单链表
	while(ans!=nullptr){
		cout<<ans->val<<"->";
		ans=ans->next;
	}
	cout<<"null"; 
	return 0;
}
部分代码解读
cpp 复制代码
delete dummyHead,tail; 

通过 new 动态分配的内存,如果你不显式地 delete,该节点的内存将不会被回收,导致内存泄漏。

LeetCode 热题 100_删除链表的倒数第 N 个结点(29_19)原题链接

欢迎大家和我沟通交流(✿◠‿◠)

相关推荐
九久。17 分钟前
手动实现std:iterator/std:string/std::vector/std::list/std::map/std:set
c++·stl
小羊羊Python19 分钟前
Sound Maze - 基于 SFML+C++14 的音效迷宫开源游戏 | MIT 协议
c++·游戏·开源
努力学算法的蒟蒻25 分钟前
day58(1.9)——leetcode面试经典150
算法·leetcode·面试
txinyu的博客28 分钟前
HTTP服务实现用户级窗口限流
开发语言·c++·分布式·网络协议·http
代码村新手28 分钟前
C++-类和对象(上)
开发语言·c++
txinyu的博客39 分钟前
map和unordered_map的性能对比
开发语言·数据结构·c++·算法·哈希算法·散列表
im_AMBER1 小时前
Leetcode 101 对链表进行插入排序
数据结构·笔记·学习·算法·leetcode·排序算法
予枫的编程笔记1 小时前
【Java集合】深入浅出 Java HashMap:从链表到红黑树的“进化”之路
java·开发语言·数据结构·人工智能·链表·哈希算法
mjhcsp1 小时前
C++ 后缀数组(SA):原理、实现与应用全解析
java·开发语言·c++·后缀数组sa
hui函数1 小时前
如何解决 pip install 编译报错 ‘cl.exe’ not found(缺少 VS C++ 工具集)问题
开发语言·c++·pip