Smaller And Smarter Python数据结构:链表倒数第K个元素+检测单链表环算法

简介: Smaller And Smarter Python数据结构:链表倒数第K个元素+检测单链表环算法

简说Python,号主老表,Python终身学习者,数据分析爱好者,从18年开始分享Python知识,原创文章227篇,写过Python、SQL、Excel入门文章,也写过Web开发、数据分析文章,老表还总结整理了一份2022Python学习资料和电子书资源,关注后私信回复:2022 即可领取。

今天给大家分享的书籍《Python程序员面试算法宝典》第一章第五小节:找出单链表中的倒数第K个元素和第一章第六节:检测一个较大链表是否有环。如果你是第一次看,也许,你可以看看本系列下面的文章:

Smaller And Smarter Python数据结构:链表逆转Smaller And Smarter Python数据结构:删除无序链表重复结点Smaller And Smarter Python数据结构:链表相加Smaller And Smarter Python数据结构:链表进行重新排序

今日问题 :单链表中的倒数第k个元素

"""
目标:写一段程序,找出单链表中的倒数第k个元素
例如:
输入 k = 3
输入-> 1->2->6->4->5
输出 6
Goal: write a program to find the last K element in the single linked list
For example:
Input k = 3
Input - > 1 - > 2 - > 6 - > 4 - > 5
Output 6
"""

解题准备

首先我们写好链表的基本操作,在a_0_base.py文件中,目前包含对链表的定义类,初始化函数,遍历函数。(带头结点)

# -*- coding: utf-8 -*-
"""
@author = 老表
@date = 2019-10-19
@个人微信公众号 : 简说Python
"""
# 链表数据结构定义
class ListNode:
    def __init__(self, x):
        self.data = x
        self.next = None
class ListOperation:
    # 根据链表数据初始化链表
    @staticmethod
    def init_list(n_list):
        # 初始化一个头指针
        head = ListNode("head")
        cur = head
        for i in n_list:
            node = ListNode(i)
            cur.next = node
            cur = node  # 相当于 cur = cur.next,后移
        return head
    # 遍历链表,带头结点
    @staticmethod
    def ergodic_list(head):
        cur = head.next
        while cur:
            print(cur.data)
            cur = cur.next
    # 获取链表长度
    @staticmethod
    def get_len_list(head):
        cur = head.next
        len_list = 0
        while cur:
            len_list = len_list + 1
            cur = cur.next
        return len_list

解题

开始程序前需提前导入前面写好的链表基本操作包和结点数据结构,在Linked_list的a_0_base.py中。

from Linked_list.a_0_base import ListOperation

方法一:顺序遍历查找

解题思路

"""
Method One : 顺序遍历查找
核心思想:假设单链表长度为:len,我们要找单链表的倒数第k个结点,
可以转化为我们要找当链表的第len-k个结点,这样,题目就变成了遍历
单链表的简单问题。
时间复杂度:O(N)
空间复杂度:O(1)
"""

代码

def find_last_k_one(head, k):
    cur_node = head.next  # 获取链表第一个结点
    order = len_list - k  # 获取链表倒数第k个结点就相当于获取链表第len_list - k 个结点
    while cur_node and order > 0:  # 遍历链表,找出第len_list - k 个结点
        cur_node = cur_node.next  # 后移遍历
        order = order - 1  # 记录遍历结点数
    return cur_node, k  # 返回k和倒数第k个结点

方法二:快慢指针法

解题思路

"""
Method Two :快慢指针法
核心思想:建一个快指针,一个慢指针,快指针比慢指针先移动k步,
然后快、慢指针一起往后移动,最终当快指针遍历完成时,慢指针指
的位置就刚好。
时间复杂度:O(N)
空间复杂度:O(1)
"""

代码

def find_last_k_two(head, k):
    fast_node = head.next  # 设置快指针
    slow_node = head.next  # 设置慢指针
    temp = k  # 临时遍量
    while fast_node:  # 遍历
        fast_node = fast_node.next  # 快指针后移
        temp = temp - 1  # temp减一,记录遍历次数
        if temp < 0:  # 遍历次数过k次后,慢指针也开始遍历,相当于快指针先后移k次
            slow_node = slow_node.next  # 慢指针后移
    return slow_node  # 返回倒数第k个结点

方法三:递归查找

解题思路

"""
Method Three :递归查找
核心思想:很烧脑袋的一种方法,先用递归遍历到表尾,
然后在回溯时候记录回溯次数,当回溯到第k次时,获取
当前结点,并返回,继续回溯直至结束。
问题:怎么去改变回溯后的k值并记录
解决:把k值作为返回值之一
当然也可以用其他方法,如:用if语句隔开递归和k值判断
时间复杂度:O(N)
空间复杂度:O(1)
"""

代码

"""
Method Three :递归查找
核心思想:很烧脑袋的一种方法,先用递归遍历到表尾,
然后在回溯时候记录回溯次数,当回溯到第k次时,获取
当前结点,并返回,继续回溯直至结束。
问题:怎么去改变回溯后的k值并记录
解决:把k值作为返回值之一
当然也可以用其他方法,如:用if语句隔开递归和k值判断
时间复杂度:O(N)
空间复杂度:O(1)
"""

测试代码

# 当然,也许还有别的方法,比如建一个辅助的链表
# 欢迎你说出你的想法
# 程序入口,测试函数功能
if __name__ == "__main__":
    list_data = [1, 2, 3, 4, 5, 6]  # 链表初始化数据
    head = ListOperation.init_list(list_data)  # 初始化链表,带头结点
    ListOperation.ergodic_list(head)  # 未逆转前,遍历打印链表
    len_list = ListOperation.get_len_list(head)  # 获取链表长度
    k = int(input("请输入参数K in (0, %d] : " % len_list))  # 输入参数k值
    while k > len_list:  # 基本判断,过滤
        print("k值过大,k in (0, %d]" % len_list)
        k = int(input("请重新输入参数K:"))
    # result = find_last_k_one(head, k)  # 测试方法一,逆转链表
    # result = find_last_k_two(head, k)  # 测试方法二,逆转链表
    result = find_last_k_three(head, k)  # 测试方法三,逆转链表
    print("---------------------")
    print("链表倒数第{0}个元素为:{1}".format(k, result[0].data))

今日问题 :检测单链表是否有环

"""
目标:写一段程序,检测一个较大的单链表是否有环
例如:
输入-> 1->2->6->4->5->2 (表示结点地址)
输出 环结点:2
Goal: write a program to check whether a large single chain table has rings
For example:
Input - > 1 - > 2 - > 6 - > 4 - > 5 - > 2 (表示结点地址)
Output ring node: 2
"""

解题准备

首先我们写好链表的基本操作,在a_0_base.py文件中,目前包含对链表的定义类,初始化函数,遍历函数。(带头结点)

# -*- coding: utf-8 -*-
"""
@author = 老表
@date = 2019-10-19
@个人微信公众号 : 简说Python
"""
# 链表数据结构定义
class ListNode:
    def __init__(self, x):
        self.data = x
        self.next = None
class ListOperation:
    a = 1
    # 根据链表数据初始化链表
    @staticmethod
    def init_list(n_list):
        # 初始化一个头指针
        head = ListNode("head")
        cur = head
        for i in n_list:
            node = ListNode(i)
            cur.next = node
            cur = node  # 相当于 cur = cur.next,后移
        return head
    # 根据链表数据初始化一个有环的链表
    @staticmethod
    def init_ring_list(n_list):
        # 初始化一个头指针
        head = ListNode("head")
        cur = head
        for i in n_list:
            node = ListNode(i)
            cur.next = node
            cur = node  # 相当于 cur = cur.next,后移
        cur.next = head.next.next.next.next  # 随意的,让最后一个结点指向第四个结点
        return head
    # 遍历链表
    @staticmethod
    def ergodic_list(head):
        # print(head.data)
        cur = head.next
        while cur:
            print(cur.data)
            cur = cur.next
    # 获取链表长度
    @staticmethod
    def get_len_list(head):
        cur = head.next
        len_list = 0
        while cur:
            len_list = len_list + 1
            cur = cur.next
        return len_list

解题

开始程序前需提前导入前面写好的链表基本操作包和结点数据结构,在Linked_list的a_0_base.py中。

from Linked_list.a_0_base import ListOperation

借助辅助空间顺序遍历查找

解题思路

"""
Method One : 借助辅助空间
核心思想:遍历链表,同时将每个结点存入到哈希表中,
并判断当前结点在不在哈希表中,如果在,则证明有环,
否则继续遍历。
时间复杂度:O(N)
空间复杂度:O(N)
"""

代码

def check_ring_one(head):
    if not head.next:  # 空链表肯定不存在环
        return None  # 直接返回False
    cur_node = head.next  # 记录第一个结点,后面做前驱结点
    dict_all = {cur_node: "node"}  # 直接把第一个结点加入字典
    while cur_node.next:  # 遍历链表
        cur_node = cur_node.next  # 后移遍历
        if cur_node in dict_all:  # 判断当前结点是否在字典中
            return cur_node  # 如果在,说明有环
        dict_all[cur_node] = "node"  # 不再,将该结点加入字典
    return None  # 遍历完成,没有触发有环判断,则说明没环,返回None

方法二:快慢指针法

解题思路

"

""
Method Two :快慢指针法
核心思想:建一个快指针,一个慢指针,快指针每次移动两步,慢指针每次
移动一步,当快指针和慢指针相同时,则说明有环,否则无环。
时间复杂度:O(N)
空间复杂度:O(1)
"""

代码

def check_ring_two(head):
    if not head.next:  # 空链表肯定不存在环
        return None  # 直接返回False
    fast_node = head.next  # 快指针,初始值为第一个结点
    slow_node = head.next  # 慢指针,初始值为第一个结点
    while slow_node:  # 遍历查找
        slow_node = slow_node.next  # 慢指针,每次位移一
        fast_node = fast_node.next.next  # 快指针,每次位移二
        if slow_node == fast_node:  # 判断快慢指针是否相同
            return slow_node  # 相同,则有环,返回该结点
    return None  # 否则无环,返回None

本文代码思路部分来自书籍《Python程序员面试宝典》,书中部分代码有问题或未提供代码,文中已经修改过了,并添加上了丰厚的注释,方便大家学习,后面我会把所有内容开源放到Github上,包括代码,思路,算法图解(手绘或者电脑画),时间充裕的话,会录制视频。希望大家多多支持。大家好,我是老表

觉得本文不错的话,转发、留言、点赞,是对我最大的支持。

相关文章
|
5天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
56 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
12天前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
12天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
30 5
|
23天前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
71 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
23天前
|
机器学习/深度学习 人工智能 算法
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
手写数字识别系统,使用Python作为主要开发语言,基于深度学习TensorFlow框架,搭建卷积神经网络算法。并通过对数据集进行训练,最后得到一个识别精度较高的模型。并基于Flask框架,开发网页端操作平台,实现用户上传一张图片识别其名称。
67 0
【手写数字识别】Python+深度学习+机器学习+人工智能+TensorFlow+算法模型
|
23天前
|
机器学习/深度学习 人工智能 算法
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
蔬菜识别系统,本系统使用Python作为主要编程语言,通过收集了8种常见的蔬菜图像数据集('土豆', '大白菜', '大葱', '莲藕', '菠菜', '西红柿', '韭菜', '黄瓜'),然后基于TensorFlow搭建卷积神经网络算法模型,通过多轮迭代训练最后得到一个识别精度较高的模型文件。在使用Django开发web网页端操作界面,实现用户上传一张蔬菜图片识别其名称。
67 0
基于深度学习的【蔬菜识别】系统实现~Python+人工智能+TensorFlow+算法模型
|
28天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
39 2
|
1月前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
43 0
|
2月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
64 4
|
5月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【7月更文挑战第22天】在大数据领域,Python算法效率至关重要。本文深入解析时间与空间复杂度,用大O表示法衡量执行时间和存储需求。通过冒泡排序(O(n^2)时间,O(1)空间)与快速排序(平均O(n log n)时间,O(log n)空间)实例,展示Python代码实现与复杂度分析。策略包括算法适配、分治法应用及空间换取时间优化。掌握这些,可提升大数据处理能力,持续学习实践是关键。
128 1