剑指offer系列-面试题22-链表中倒数第k个节点(python)

文章目录

  • 1.题目
  • 2. 解题思路
  • 3. 代码实现
    • 3.1 常规思路
    • 3.2 更优思路
  • 4.总结
  • 5.参考文献

1.题目

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第一个节点。例如,一个链表有6个节点,从头节点开始,他们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。链表的定义如下:

struct ListNode
{
	int m_nValue;
	ListNode* m_pNext;
};

当然对于python而言,链表的定义如下:

class ListNode(object):
	def __init__(self, value, next_node):
		self.value = value
		self.next = next_node

2. 解题思路

我看过这个题之后的思路就是,因为这个单链表,不是双向链表,因此要获得某一个节点,那么只能遍历,而且,一开始我们并不知道倒数第k个节点是哪一个,只有在遍历过一边链表之后,才能知道倒数第k个节点在哪儿。过程就是,第一次遍历链表得到链表的长度,计算出倒数第k个节点是顺数第几个节点(因为我们无法按照倒数来获得这个节点), 然后在再一次遍历这个链表,知道到达这个节点。时间复杂度O(n^2),空间复杂度S(1)。

上面的方法很简单,但是时间复杂度是O(n^2),面试官不会满意的,那么能不能降低时间复杂度呢?定义两个指针:第一个指针从链表头部开始遍历向前走k-1步,第二个指针保持不动;从第k步开始,第二个指针也开始从链表的头部开始遍历。两个指针的距离是k-1,当第一个指针到达链表的尾节点时,由于这两个节点的距离始终是k-1,这时第二个指针正好指向倒数第k个节点

3. 代码实现

3.1 常规思路

def find_kth_to_tail(head, k):
	count = 0 # 链表的长度
	if k <= 0:
		return
	if head:
		cur = head # 当前节点
		while cur:
			count += 1
			cur = cur.next
	
		# 倒数第k个节点是顺数的第n-k+1这个节点
		index = count - k + 1
	if index < 1:
		return 
	cur = head
	while index > 1:
		cur = cur.next
		index -= 1
	return cur

3.2 更优思路

def find_kth_to_tail(head, k):
	count = 1 # 第几个节点
	cur = head # 指针1
	k_node = head # 指针2
	if k <= 0: # 负值条件,返回None
		return 
	while cur:
		cur = cur.next
		if count > k: # 从顺数第k+1个节点开始,同时移动cur和k_node
			k_node = k_node.next
		count += 1
	if count < k: # 若k>链表长度,应该返回None
		return 
	return k_node 
			
		
def find_kth_to_tail(head, k):
	count = 1 # 第几个节点
	cur = head
	k_node = head
	if k <= 0:
		return
	while count < k: # count最后的值为k
		if cur:
			cur = cur.next
			count += 1
		else:
			return 
	# 此时cur指向顺数第k个节点,而k_node指向第一个节点(头节点),当cur指向尾节点时终止。
	while cur.next:
		cur = cur.next
		k_node = k_node.next 
	return k_node
	

4.总结

当我们用一个指针遍历链表不能解决问题的时候,可以考虑使用两个指针来遍历链表,然后控制两个指针的速度或者某个指针先出发。
而对于列表而言,指针一般是从两端往中间移动。

5.参考文献

[1]剑指offer丛书

你可能感兴趣的:(算法)