链表问题02:在单链表和双链表中删除倒数第K个节点

这篇博客介绍了如何在单链表和双链表中高效地删除倒数第K个节点。针对单链表,通过两次遍历确定待删除节点的前一个节点,并进行删除操作。对于双链表,处理方式类似,主要区别在于处理节点的连接。要求的时间复杂度为O(N),额外空间复杂度为O(1)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目】

        分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点。

 

【要求】

        如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1)。

 

【解答-单链表】

        如果链表为空或者K值小于1,这种情况下,参数是无效的,直接返回即可。除此之外,让链表从头开始走到尾,每移动一步,就让K的值减1。

        链表:1 -> 2 -> 3,K=4,链表根本不存在倒数第4个节点。

        走到的节点:1 -> 2 -> 3

        K的变化:3 2 1

        链表:1 -> 2 -> 3,K=3,链表倒数第3个节点是1节点

        走到的节点:1 -> 2 -> 3

        K的变化:2 1 0

        链表:1 -> 2 -> 3,K=2,链表倒数第2个节点是2节点

        走到的节点:1 -> 2 -> 3

        K的变化:1 0 -1

        由以上三种情况可知,让链表从头开始走到尾,每移动一步,就让K值减1,当链表走到结尾时,如果K值大于0,说明不用调整链表,因为链表根本没有倒数第K个节点,此时将原链表直接返回即可;如果K值等于0,说明链表倒数第K个节点就是第一个节点(head),此时直接返回head->next,也就是原链表的第二个节点,让第二个节点作为链表的头返回即可,相当于删除第一个节点;接下来,说明以下如果K值小于0,该如何处理。

        先明确一点,如果要删除链表的头节点之后的某个节点,实际上需要找到要删除节点的前一个节点,比如:1 -> 2 -> 3,如果要删除节点2,则需要找到节点1,然后把节点1连到节点3上(1 -> 3),以此来达到删除节点2的目的。

        如果K值小于0,如何找到要删除节点的前一个节点呢?方法如下:

      (1)重新从头节点开始走,每移动一步,就让K的值加1。

      (2)当K等于0时,移动停止,移动到的节点就是要删除节点的前一个节点。

        这样做是非常好理解的,因为如果链表长度为N,要删除倒数第K个节点,很明显,倒数第K个节点的前一个节点就是第N-K个节点。在第一次遍历后,K的值变为K-N。第二次遍历时,K的值不断加1,加到0就停止遍历,第二次遍历当然会停到第N-K个节点的位置。

 

【代码实现】

struct Node{
	int value;
	Node *next;
	Node(int data){
		value = data;
	}
};


static Node *removeLastKthNode(Node *head, int lastKth){
	if (head == nullptr || lastKth < 1){
		return head;
	}

	Node *cur = head;
	while (cur != nullptr){
		lastKth--;
		cur = cur -> next;
	}
	if (lastKth == 0){
		head = head -> next;
	}
	if (lastKth < 0){
		cur = head;
		while (++lastKth != 0){
			cur = cur->next;
		}
		cur->next = cur->next->next;
	}
	return head;
}

 

对于双链表的调整,几乎和单链表的处理方式一样,注意last指针的重连即可。

 

【代码实现】

struct DoubleNode
{
	int value;
	DoubleNode *last;
	DoubleNode *next;
	DoubleNode(int data){
		value = data;
	}
};


static DoubleNode *removeLastKthNode(DoubleNode *head, int lastKth){
	if (head == nullptr || lastKth < 1){
		return head;
	}
	DoubleNode *cur = head;
	while (cur != nullptr){
		lastKth--;
		cur = cur->next;
	}
	if (lastKth == 0){
		head = head->next;
		head->last = nullptr;
	}
	if (lastKth < 0){
		cur = head;
		while (++lastKth != 0){
			cur = cur->next;
		}
		DoubleNode *newNext = cur->next->next;
		cur->next = newNext;
		if (newNext != nullptr){
			newNext->last = cur;
		}
	}
	return head;
}

 

【来源】

《程序员代码面试指南(IT名企算法与数据结构题目最优解)》左程云

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值