python算法-006从无序链表中移除重复项(HashSet空间换时间)

你的问题主要在于读书不多而想的太多。——杨绛

这句话说的真是太对了,我一定多读书!!!


题目:给定一个无序链表,例如:head->1->2>1-->3->3->5->7->6>7->8,删除其中的重复项,将其变成head->1->2->5->7->6->8。


今天的题目与昨天的题目是相同的,昨天我们用的顺序删除法,成功的完成了这个任务。但是其采用双重循环来遍历链表,时间复杂度为O(N^2)。通常情况下,为了降低时间复杂度,往往再条件允许的情况下,通过使用辅助空间来实现。具体如下:

题目要求去除重复项,我们很容易想到Python自己的一种数据类型——集合set。集合具有无序性、唯一性、确定性。无序性:集合中的元素的地位相同,没有顺序。唯一性:也叫互异性,集合元素两两各不相同,每个元素只能出现一次。确定性:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现。

我们利用集合的唯一性就可以解决——“当前节点是否重复出现过”这一问题了。我们先建立一个HashSet集合,HashSet用来存储已经遍历过的节点的内容。先将其初始化为空。然后从头开始遍历链表,然后判断当前节点的内容是否在HashSet中。如果在,则把当前节点删除;如果不在,保留当前节点,并将当前节点的内容添加到HashSet中,遍历下一个节点,直到链表为空。

这种方法的时间复杂度为O(n),因为只需要遍历一次链表。下面用代码实现:

def RemoveDup(head):
    """
    空间换时间
    无头节点
    """
    #先判断链表是否为空或者
    if head.next is None:
        return head
    Hashset=set()#保存已经遍历过的内容
    Hashset.clear()#初始化集合
    pre=head#指向当前节点的前驱节点,用于删除当前节点
    cur=head.next#用于遍历链表,指向当前节点
    #遍历链表
    while cur is not None:
        #如果当前节点的值不在HashSet中,则将其存到HashSet中
        if cur.data not in Hashset:     
            Hashset.add(cur.data)
            #遍历下一个节点
            cur=cur.next
            pre=pre.next
        else:
            #如果当前节点的值在HashSet中,则删除节点
            pre.next=cur.next
            cur=cur.next
    #返回处理完成的链表
    return head

至于如何删除当前节点,这个问题我在昨天的文章里写的很清楚了这里就不在赘述——python算法-005从无序链表中移除重复项(顺序删除法)

与之前一样先构造一个无序链表(昨天也讲了,可以看看前面的链接),用于检验我们的算法:

#先引入random库
import random
#依然是先定义节点类
class LNode(object):
    def __init__(self, arg):
        self.data = arg
        self.next = None
#这里!前几篇的create我写错了,少了个e,
#这里改用construct 构造的意思
def construstLink(x):
    i = 1
    head = LNode(None)
    tmp = None
    cur = head
    while i <= x:
        #这里与之前不同,先生成一个随机数,作为节点值
        n = random.randint(0, 9)
        tmp = LNode(n)
        cur.next = tmp
        cur = tmp
        i += 1
    return head

主程序:

if __name__ == '__main__':
    #构造链表
    head=construstLink(10)
    #打印处理之前的链表
    print("BeforeReverse:")
    cur = head.next
    while cur != None:
        print(cur.data)
        cur = cur.next
    #调用算法,处理链表
    head = RemoveDup(head)
    # 打印处理之后的链表
    print("\nAfterReverse:")
    cur = head.next
    while cur != None:
        print(cur.data)
        cur = cur.next

下面的是运行结果:


成功的去除了3个3

你也可以多试几次,我这算法是对的。


这是全部的代码:

import random
class LNode(object):
    """docstring for LNode"""
    def __init__(self, arg):
        self.data = arg
        self.next = None

#这里!前几篇的create我写错了,少了个e,
#这里改用construct 构造的意思
def construstLink(x):
    i = 1
    head = LNode(None)
    tmp = None
    cur = head
    while i <= x:
        #这里与之前不同,先生成一个随机数,作为节点值
        n = random.randint(0, 9)
        tmp = LNode(n)
        cur.next = tmp
        cur = tmp
        i += 1
    return head
"""
题目描述:
将Head->1->1->3->3->5->7->7->8变
为head->1->2->5->7->8
方法:空间换时间,利用集合的无序性、唯一性
"""
def RemoveDup(head):
    """
    空间换时间
    无头节点
    """
    #先判断链表是否为空或者
    if head.next is None:
        return head
    Hashset=set()#保存已经遍历过的内容
    Hashset.clear()#初始化集合
    pre=head#指向当前节点的前驱节点,用于删除当前节点
    cur=head.next#用于遍历链表,指向当前节点
    #遍历链表
    while cur is not None:
        #如果当前节点的值不在HashSet中,则将其存到HashSet中
        if cur.data not in Hashset:     
            Hashset.add(cur.data)
            #遍历下一个节点
            cur=cur.next
            pre=pre.next
        else:
            #如果当前节点的值在HashSet中,则删除节点
            pre.next=cur.next
            cur=cur.next
    #返回处理完成的链表
    return head

if __name__ == '__main__':
    #构造链表
    head=construstLink(10)
    #打印处理之前的链表
    print("BeforeRemoveDup:")
    cur = head.next
    while cur != None:
        print(cur.data)
        cur = cur.next
    #调用算法,处理链表
    head = RemoveDup(head)
    # 打印处理之后的链表
    print("\nAfterRemoveDup:")
    cur = head.next
    while cur != None:
        print(cur.data)
        cur = cur.next

今天的算法就这样,明天讲一讲如何用递归来实现这种操作,大家可以先试一试。我目前也是在学习阶段,还有存在很多问题,望各位不吝赐教。我写这类文章,一是为了能够更好的理解我学的东西,毕竟自己能讲出来,也是很不错了;二呢,是为了与大家分享我的学习成果,一起学习一起进步,一起走向人生巅峰(哈哈哈,当然光学这个,那是连工作都不一定能找到);还有一点就是:有一件能够坚持的事情也是很幸福的!

当然大家有什么需要都可以来找我,简书号、微信公众号:Dkider 私信、简信,都可以找到我。
更多的问题以及文章源码见github

要人知道自己有个秘密,而不让人知道是个什么秘密,等他们问,要他们猜,这是人性的虚荣。——钱钟书《围城》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270