Smaller And Smarter Python数据结构:删除无序链表重复结点

简介: Smaller And Smarter Python数据结构:删除无序链表重复结点

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

今天给大家分享的书籍《Python程序员面试算法宝典》第一章第二小节:删除无序链表重复结点。

如果你是第一次看,也许,你可以看看本系列下面的文章:

Smaller And Smarter Python数据结构:链表逆转

今日问题

"""
目标:写一段程序,从无序链表中移除重复项
例如:
输入-> 1->0->3->1->4->5->1->8
输出-> 1->0->3->4->5->8
"""
"""
Goal: write a program to remove duplicates from the unordered list
For example:
Input - > 1 - > 0 - > 3 - > 1 - > 4 - > 5 - > 1 - > 8
Output - > 1 - > 0 - > 3 - > 4 - > 5 - > 8
"""

首先我们写好链表的基本操作,在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

解题

开始程序前需提前导入前面写好的链表基本操作包a_0_base

from Linked_list.a_0_base import ListOperation
方法一:递归去重
"""
Method One : 递归去重
核心思想:每次遍历去重前,都先对子链表进行去重处理,
这样去重的子链表都会产生一个子链表,直到递归到尾结
点,此时开始回溯,每次回溯,会完成一个子链的去重,
直到回溯到头结点,链表去重完成。
时间复杂度:O(N^2)
空间复杂度:O(1)
"""
代码
def remove_duplicates_one(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # 空链表或者遍历到最后一个结点
        return head  # 返回头结点或者开始回溯
    cur_node = head  # 记录头结点
    head.next = remove_duplicates_one(head.next)   # 递归,往后遍历
    # print("此时cur_node=", cur_node.data)
    # print("此时head=", head.data)
    pointer = head.next  # 记录后继结点
    # print("此时pointer=", pointer.data)
    # 遍历查找
    while pointer:   # 遍历当前子链表
        if head.data == pointer.data:
            cur_node.next = pointer.next  # 删除相同结点
            pointer = cur_node.next  # 后移,遍历子链表
        else:
            pointer = pointer.next  # 后移,遍历子链表
            cur_node = cur_node.next  # 当前结点后移
    # print("此时head=", head.data)
    # print("____________________________")
    return head  # 返回当前子链表头结点
方法二:顺序删除
"""
Method Two : 顺序删除
核心思想:你要是搞清楚方法一,这个就不难理解了。
直接利用双循环,一个慢指针,一个快指针,匹配到
快慢指针的数据值相同时就删除该快指针,然后继续
遍历快指针,直至结束,然后慢指针后移,继续遍历。
时间复杂度:O(N^2)
空间复杂度:O(1)
"""
代码
def remove_duplicates_two(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # 空链表或者遍历到最后一个结点
        return head  # 返回头结点或者开始回溯
    slow_node = head.next  # 记录慢指针(外层循环)
    while slow_node:  # 外层遍历
        fast_node = slow_node.next  # 记录快指针(内层遍历)
        cur_node = slow_node  # 记录当前结点,方便删除结点
        while fast_node:  # 内层遍历
            if fast_node.data == slow_node.data:  # 在子链中查找值与slow_node一样的结点(值重复结点)
                cur_node.next = fast_node.next  # 删除重复结点(让当前结点的next指向重复结点的next)
            else:
                cur_node = fast_node  # 当前结点后移,继续遍历子链
            fast_node = fast_node.next  # 后移,继续遍历子链(快指针)
        slow_node = slow_node.next  # 后移,继续遍历(慢指针)
    return head  # 返回当前子链表头结点
方法三:空间换时间
"""
Method Three : 空间换时间
核心思想:建一个辅助栈记录链表数据项,遍历链表,
1、如果当前结点的数据项在辅助栈中,则删除该结点
2、如果当前结点数据项不在辅助栈中,则该结点数据项
进行入栈操作
3、继续遍历,直至遍历结束。
辅助栈可选数据类型:元祖,列表,字典,集合
其中字典和集合的查找时间复杂度为O(1),字典内部是有哈希表
(哈希函数+哈希冲突表)构成,故查找时间复杂度为O(1),
Python里集合的内部实现是字典,故查找时间复杂度也为O(1)。
时间复杂度:O(N)
空间复杂度:O(N)
"""
代码
def remove_duplicates_three(head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    if not head.next:  # 空链表或者遍历到最后一个结点
        return head  # 返回头结点或者开始回溯
    run_node = head.next.next  # 从第二个结点开始遍历(因为第一个结点肯定不存在重复问题)
    pre_node = head.next  # 记录第一个结点,后面做前驱结点
    dict_all = {pre_node.data: "node"}  # 直接把第一个结点数据项加入字典,键值任意给
    while run_node:  # 遍历链表
        if run_node.data in dict_all:  # 判断当前遍历结点值在不在字典中
            pre_node.next = run_node.next  # 删除重复结点(让当前结点的next指向重复结点的next)
        else:  # 不在字典中,则入栈,并让前驱结点后移
            dict_all[run_node.data] = "node"
            pre_node = run_node
        run_node = run_node.next  # 后移遍历
    # print(dict_all)
    return head  # 返回当前子链表头结点

测试代码

# 当然,也许还有别的方法,比如建一个辅助的链表
# 欢迎你说出你的想法
# 程序入口,测试函数功能
if __name__ == "__main__":
    s0 = ListOperation()  # 初始化一个链表基本操作对象实例
    list_data = [1, 2, 3, 4, 2, 3, 9, 1]  # 链表初始化数据
    head = s0.init_list(list_data)  # 初始化链表,带头结点
    s0.ergodic_list(head)  # 未逆转前,遍历打印链表
    # head = remove_duplicates_one(head)  # 测试方法一,逆转链表
    # head = remove_duplicates_two(head)  # 测试方法二,逆转链表
    head = remove_duplicates_three(head)  # 测试方法三,逆转链表
    print("---------------------")
    s0.ergodic_list(head)  # 逆转后,遍历打印链表

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

希望大家多多支持。

大家好,我是老表

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

相关文章
|
5月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
159 1
|
算法
【❤️算法笔记❤️】-每日一刷-19、删除链表的倒数第 N个结点
【❤️算法笔记❤️】-每日一刷-19、删除链表的倒数第 N个结点
260 1
|
8月前
|
存储 Python
Python 中链表的个人理解
简介:本文介绍了Python中链表的基本组成及其操作实现。链表由`head`(头节点)、中间节点和`tail`(尾节点)三部分构成,每个节点通过`Node`类定义,包含`value`(值域)和`next`(指针域)。示例代码展示了链表的增删查功能,包括`add`(头部插入)、`append`(尾部插入)、`remove`(删除节点)、`search`(查找节点)及遍历方法。运行结果验证了链表操作的正确性。
|
10月前
|
存储 Python
Python 实现单向链表,和单向链表的反转
链表是一种数据结构,每个节点存储相邻节点的位置信息。单链表中的节点仅存储下一节点的位置。通过Python实现单链表,定义`ListNode`类并关联节点可创建链表。例如,创建A->B->C的链表后,可通过反转函数`reverse`将链表反转为CBA。代码展示了如何实现和操作单链表。
216 6
Python 实现单向链表,和单向链表的反转
|
10月前
|
存储 算法 搜索推荐
Python 实现反转、合并链表有啥用?
大家好,我是V哥。本文介绍Python实现反转链表和合并链表的应用场景及代码实现。反转链表适用于时间序列数据展示、回文链表判断等;合并链表则用于大规模数据排序、数据库查询结果集合并等。通过迭代和递归方法实现反转链表,以及合并两个或多个有序链表的算法,帮助开发者解决实际问题。关注V哥,了解更多实用编程技巧。 先赞再看后评论,腰缠万贯财进门。
191 0
链表的中间结点
链表的中间结点
385 57
|
11月前
|
Python
探索 Python 中链表的实现:从基础到高级
链表是一种由节点组成的基础数据结构,每个节点包含数据和指向下一个节点的引用。本文通过Python类实现单向链表,详细介绍了创建、插入、删除节点等操作,并提供示例代码帮助理解。链表在处理动态数据时具有高效性,适用于大量数据变动的场景。文章为初学者提供了全面的入门指南,助你掌握链表的核心概念与应用。
550 0
|
存储 算法 搜索推荐
链表的中间结点
【10月更文挑战第24天】链表的中间结点是链表操作中的一个重要概念,通过快慢指针法等方法可以高效地找到它。中间结点在数据分割、平衡检测、算法应用等方面都有着重要的意义。在实际编程中,理解和掌握寻找中间结点的方法对于解决链表相关问题具有重要价值。
278 1
【LeetCode 09】19 删除链表的倒数第 N 个结点
【LeetCode 09】19 删除链表的倒数第 N 个结点
191 0
|
Python
【Leetcode刷题Python】剑指 Offer 22. 链表中倒数第k个节点
Leetcode题目"剑指 Offer 22. 链表中倒数第k个节点"的Python解决方案,使用双指针法找到并返回链表中倒数第k个节点。
195 5

热门文章

最新文章

推荐镜像

更多