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)原题链接

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

相关推荐
hefaxiang3 小时前
【C++】函数重载
开发语言·c++·算法
花生树什么树3 小时前
下载Visual Studio Community 2019
c++·visual studio·vs2019·community
exp_add33 小时前
Codeforces Round 1000 (Div. 2) A-C
c++·算法
练小杰4 小时前
Linux系统 C/C++编程基础——基于Qt的图形用户界面编程
linux·c语言·c++·经验分享·qt·学习·编辑器
勤又氪猿4 小时前
【问题】Qt c++ 界面 lineEdit、comboBox、tableWidget.... SIGSEGV错误
开发语言·c++·qt
Ciderw4 小时前
Go中的三种锁
开发语言·c++·后端·golang·互斥锁·
人才程序员6 小时前
【C++拓展】vs2022使用SQlite3
c语言·开发语言·数据库·c++·qt·ui·sqlite
OKkankan6 小时前
实现二叉树_堆
c语言·数据结构·c++·算法
Ciderw7 小时前
MySQL为什么使用B+树?B+树和B树的区别
c++·后端·b树·mysql·面试·golang·b+树
yerennuo7 小时前
windows第七章 MFC类CWinApp介绍
c++·windows·mfc