链表OJ3——链表中倒数第k个结点

声明:我的链表OJ系列是针对无头单向不循环链表的题目

题目

题目来源:输出单向链表中倒数第k个结点_牛客题霸_牛客网

描述

输入一个单向链表,输出该链表中倒数第k个结点。

思路一——直接遍历

由于这道题目并没有要求时间复杂度,我们完全可以先遍历一遍链表,得到链表的结点总数(count),然后再遍历一遍链表,从第一个结点开始,后面的第count - k个结点即为目标结点

但是在求解过程中有两个情况需要中途便返回NULL:
1.当传入的链表为空时,直接返回空(NULL)。
2.当计算出的链表总结点数count小于k时,返回空(NULL)。

代码实现

struct ListNode {
	int val;
	struct ListNode *next;
};

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k)
{
	if (pListHead == NULL)//判断链表是否为空
		return NULL;
	struct ListNode* cur = pListHead;//记录当前结点位置
	int count = 0;//记录链表的总结点数
	while (cur)
	{
		count++;//结点总数加一
		cur = cur->next;//指针后移
	}
	if (count < k)//count小于k,此时不存在倒数第k个结点
		return NULL;
	struct ListNode* ret = pListHead;
	int pos = count - k;//倒数第k个结点距离第一个结点的结点数
	while (pos--)
	{
		ret = ret->next;//指针后移
	}
	return ret;//返回目标结点
}

思路二——快慢指针

我们若是仅仅为了解决这个问题,那么用上面这种解法解决这道题完全没问题。但我们若是为了提高自身的代码能力,上面这种思路是远远不够的,在实际运行时该代码的效率不高,而且这种代码在面试时根本不能“打动”面试官。

其实我们还是可以运用“快慢指针”的思想来解决这道题,这样可以使得代码的时间复杂度直接从O(n2)变为O(n) 。需要注意的是:这里所说的“快慢指针”并非一个指针走得快,另一个指针走得慢,而是快指针先走,慢指针在快指针走到某一位置后再开始走。

因为从最后一个结点开始,再往后走一步便是NULL;从倒数第二个结点开始,再往后走两步便是NULL;从倒数第k个结点开始,再往后走k步便是NULL。所以我们可以先让快指针(fast)先走k步,然后慢指针(slow)再和快指针一起往后走,这样,当快指针走到NULL时,慢指针指向的结点就是倒数第k个结点。

代码实现 

struct ListNode {
	int val;
	struct ListNode *next;
};

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k)
{
	struct ListNode* fast = pListHead;//快指针
	struct ListNode* slow = pListHead;//慢指针
	while (k--)//快指针先向后移动k步
	{
		if (fast == NULL)//快指针移动过程中链表遍历结束,不存在倒数第k个结点
			return NULL;
		fast = fast->next;//快指针后移
	}
	while (fast)//快指针遍历完链表时结束遍历
	{
		fast = fast->next;//快指针后移
		slow = slow->next;//慢指针后移
	}
	return slow;//返回慢指针的值
}

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值