题目描述:
找出单链表中的倒数第k个元素,如给定单链表:1->2->3->4->5->6->7,则单链表的倒数第k=3个元素为5
方法:
1. 顺序遍历两遍法
首先遍历一遍单链表,求出整个单链表的长度n,然后把求倒数第k个元素转换为求顺数第n-k个元素,再去遍历一次单链表就可以得到结果。但是该方法需要对单链表进行两次遍历。
2. 快慢指针法
由于单链表只能从头和尾依次访问链表的各个结点,因此,如果要找链表的倒数第 k 个元素,也只能从头到尾进行遍历查找。在查找的过程中,设置两个指针,让一种一个指针前移k步,然后两个指针同时往前移动。循环直到先行的指针值为 None 时,另一个指针所指的位置就是所要找的位置。
算法性能分析:
此方法只对链表进行一次遍历,所以时间复杂度为O(n);
另外由于只需要常量个指针变量来保存结点的地址信息,所以空间复杂度为O(1)
代码实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2020/1/16 19:35
# @Author : buu
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44321080
class LNode:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def ConstructList():
"""
构造一个单链表
:return: 链表的头结点
"""
i = 1
head = LNode()
tmp = None
cur = head
while i < 8:
tmp = LNode(i)
cur.next = tmp
cur = tmp
i += 1
return head
def PrintList(head):
"""
顺序打印单链表结点的数据
:param head: 单链表的头结点
:return:
"""
cur = head.next
print('raw list:', end=' ')
while cur is not None:
print(cur.data, end=' ')
cur = cur.next
print()
def FindLastK(head, k):
"""
找出链表倒数第k个结点
:param head: 链表头结点
:return: 倒数第k个结点
"""
if head is None or head.next is None:
return head
slow = head.next
fast = head.next
i = 0
while i < k and fast is not None: # 快指针先走k步
fast = fast.next
i += 1
if i < k: # 未走k步,快指针已到链表尾部
return None
while fast is not None:
fast = fast.next
slow = slow.next
return slow
if __name__ == '__main__':
head = ConstructList()
result = None
PrintList(head)
result = FindLastK(head, 3)
if result != None:
print('last3 is:', result.data)
结果:
引申:
如何将单链表向右旋转k个位置,即:给定单链表1->2->3->4->5->6->7,k=3,则旋转后的单链表变为5->6->7->1->2->3->4
扫描二维码关注公众号,回复: 8930682 查看本文章
思路:
- 首先找到链表倒数第k+1个结点slow和尾结点fast(如下图所示);
- 把链表断开为两个子链表,其中,后半部分链表结点的个数为k;
- 使原链表的尾结点指向链表的第一个结点(而非头结点);
- 使链表的头结点指向原链表倒数第k个结点;
算法性能分析:
这种方法只需要对链表进行一次遍历,所以时间复杂度为O(n);
此外,由于只需要几个指针变量来保存结点的地址信息,因此空间复杂度为O(1)
代码实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time : 2020/1/16 20:23
# @Author : buu
# @Software: PyCharm
# @Blog :https://blog.csdn.net/weixin_44321080
class LNode:
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def ConstructList():
"""
构造一个单链表
:return: 链表的头结点
"""
i = 1
head = LNode()
tmp = None
cur = head
while i < 8:
tmp = LNode(i)
cur.next = tmp
cur = tmp
i += 1
return head
def PrintList(head):
"""
顺序打印单链表结点的数据
:param head: 单链表的头结点
:return:
"""
cur = head.next
while cur is not None:
print(cur.data, end=' ')
cur = cur.next
print()
def RotateK(head, k):
"""
把链表右旋k个位置
:param head: 头结点
:param k: k个位置
:return:
"""
if head is None or head.next is None:
return
slow = head.next
fast = head.next
tmp = LNode()
i = 0
while i < k and fast is not None:
fast = fast.next
i += 1
if i < k:
return None
while fast.next != None: # FindLastK.py中是 fast != None
slow = slow.next # 循环结束后,slow指向倒数第k+1个元素;
fast = fast.next # fast指向最后一个元素
tmp = slow.next # tmp 指向包含后k个元素链表的首结点
slow.next = None
fast.next = head.next
head.next = tmp
if __name__ == '__main__':
head = ConstructList()
print('before rotation:', end=' ')
PrintList(head)
RotateK(head, 3)
print('after rotation:', end=' ')
PrintList(head)
结果:
end