python百题大通关解题记录-链表

目录

009实现链表类

挑战内容

010删除链表的重复项 

挑战内容

011寻找链表倒数第 k+1 个结点 

挑战内容

013对链表值进行分区

挑战内容

014对链表值进行求和

挑战内容

挑战内容


 本文题目编译自 Donne Martin 的开源项目

009实现链表类

实现链表的插入,增加,查找,删除,查看长度和打印的方法。链表的介绍如下:

  • 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
  • 链表中每一个元素称为结点,链表由一系列结点组成,结点可以在运行时动态生成。
  • 链表的每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

挑战内容

本次挑战中,你需要在 linkedlist.py 文件中补充类 Node 和类 LinkedList 的空缺部分。

  • Node 类是定义的结点类。

  • Node 中的 __init__ 方法用于初始化结点,结点包含数据元素 data 和指向下一个结点地址的指针 next_node

  • Node 中的 __str__ 方法用于返回当使用 print 输出对象时打印的信息,它需要返回结点的数据元素。

  • LinkedList 类是定义的链表类。

  • LinkedList 中的 __init__ 方法用于初始化链表,参数 head 为链表头的指针。

  • LinkedList 中的 __len__ 方法用于返回链表的结点个数,它需要返回一个数字。

  • LinkedList 中的 insert_to_front 方法用于在链表前面插入结点,参数 data 用于指定结点的数据元素,它需要返回插入的结点。如果 data 为 None 则返回 None

  • LinkedList 中的 append 方法用于在链表后面增加结点,参数 data 用于指定结点的数据元素,它需要返回增加的结点。如果 data 为 None 则返回 None

  • LinkedList 中的 find 方法用于查找链表中包含指定数据元素的结点,参数 data 用于指定结点的数据元素,它需要返回找到的结点。如果无法找到数据,则返回 None

  • LinkedList 中的 delete 方法用于删除链表中包含指定数据元素的结点,参数 data 用于指定结点的数据元素,它不需要返回任何值。如果链表没有结点,或者指定元素不在链表中,则不进行删除操作。

  • LinkedList 中的 print_list 方法用于打印链表所有结点的数据元素。它需要使用 print 函数从链表头至链表尾依次打印出结点的数据元素。

  • LinkedList 中的 get_all_data 方法用于将链表转化为数组,数组的元素为链表结点的数据元素,它需要返回一个数组。

    代码:(原环境对手打不友好,此为直接复制的答案)python链表基本操作

    class Node(object)://节点类
    
        def __init__(self, data, next=None)://节点初始化,指针域(可为None)和数据域
            self.next = next
            self.data = data
    
        def __str__(self):
            return self.data
    
    
    class LinkedList(object)://链表类
    
        def __init__(self, head=None)://初始化头结点
            self.head = head
    
        def __len__(self)://返回链表长度
            curr = self.head
            counter = 0
            while curr is not None:
                counter += 1
                curr = curr.next
            return counter
    
        def insert_to_front(self, data)://向前插入节点,必然是头结点,故不判断头结点
            if data is None:
                return None
            node = Node(data, self.head)
            self.head = node
            return node
    
        def append(self, data)://向后加入节点
            if data is None:
                return None
            node = Node(data)
            if self.head is None://判断头结点有无
                self.head = node
                return node
            curr_node = self.head
            while curr_node.next is not None:
                curr_node = curr_node.next
            curr_node.next = node
            return node
    
        def find(self, data)://查找数据,返回节点
            if data is None:
                return None
            curr_node = self.head
            while curr_node is not None:
                if curr_node.data == data:
                    return curr_node
                curr_node = curr_node.next
            return None
    
        def delete(self, data)://删除指定节点
            if data is None:
                return
            if self.head is None:
                return
            if self.head.data == data://判断头结点是否符合
                self.head = self.head.next
                return
            prev_node = self.head
            curr_node = self.head.next
            while curr_node is not None:
                if curr_node.data == data:
                    prev_node.next = curr_node.next
                    return
                prev_node = curr_node
                curr_node = curr_node.next
    
        def print_list(self):
            curr_node = self.head
            while curr_node is not None:
                print(curr_node.data)
                curr_node = curr_node.next
    
        def get_all_data(self):
            data = []
            curr_node = self.head
            while curr_node is not None:
                data.append(curr_node.data)
                curr_node = curr_node.next
            return data

010删除链表的重复项 

实现一个算法来删除链表中数据元素重复的结点。要求如下:

  • 对于链表中有相同数据元素的结点,删除后面的重复结点。

挑战内容

本次挑战中,你需要在 removedupes.py 文件中补充函数 remove_dupes 的空缺部分。

  • MyLinkedList 类继承“实现链表类”挑战中的 LinkedList 类。
  • MyLinkedList 类的 remove_dupes 方法用于删除链表的重复项,它没有输入,也没有返回值。
  • 如果链表没有结点,则不进行操作

 代码:引入链表类,并继承链表类

from linked_list import LinkedList//引用009中的链表类


class MyLinkedList(LinkedList)://继承链表类的方法属性

    def remove_dupes(self):
        if self.head is None:
            return
        node=self.head
        seen_data=set()//集合收集已经出现的数据
        while node is not None:
            if  node.data not in seen_data:
                seen_data.add(node.data)
                prev=node
                node=node.next
            else:
                prev.next=node.next
                node=node.next

011寻找链表倒数第 k+1 个结点 

实现一个算法来寻找离链表最后一个结点 k 个距离的结点,即链表倒数第 k+1 个结点,并得到此结点的数据元素。

挑战内容

本次挑战中,你需要在 kth_to_last.py 文件中补充函数 kth_to_last_elem 的空缺部分。

  • MyLinkedList 类继承“实现链表类”挑战中的 LinkedList 类。
  • MyLinkedList 类的 kth_to_last_elem 方法用于寻找离链表最后一个结点 k 个距离的结点,参数 k 用于指定距离,它需要返回结点的数据元素。
  • 如果链表没有结点,则返回 None;如果 k 大于或等于链表的长度,也返回 None

 代码:这里不使用长度计算_len_方法,而是双指针控距同步递增法

from linked_list import LinkedList


class MyLinkedList(LinkedList):

    def kth_to_last_elem(self, k):
        if self.head is None://判断链表是否为空
            return None
        fast=self.head
        slow=self.head
        for _ in range(k):
            fast=fast.next//利用快指针检查链表是否长于k,同时拉开快指针和慢指针的距离
            if fast is None:
                return None
        while fast.next is not None:
            fast=fast.next
            slow=slow.next//快慢指针同时移动,他们的距离正好是k,快指针是尾结点,慢指针是倒数k+1。
        return slow.data

013对链表值进行分区

实现一个算法来对链表中结点的元素值进行分区,使所有小于 x 的节点排在所有大于或等于 x 的节点之前。要求如下:

  • 对于给定值 x,将链表的结点的顺序排为:值小于 x 的结点,值等于 x 的结点,值大于 x 的结点。
  • 对于分区的每部分,即值小于 x 的部分和值大于 x 的部分,不需要按值的大小再进行排序,而是按照原本链表的顺序进行链接。例如值为 [4, 8, 5, 2, 5] 的链表按 5 进行分区的结果为 [4, 2, 5, 5, 8]

挑战内容

本次挑战中,你需要在 partition_data.py 文件中补充函数 partition 的空缺部分。

  • MyLinkedList 类继承“实现链表类”挑战中的 LinkedList 类。
  • MyLinkedList 类的 partition 方法用于对链表中结点的元素值进行分区,参数 data 用于指定分区的临界值,它需要返回分区后的链表。
  • 如果链表没有结点,则不进行分区操作。

 代码:创建左右两个链表进行存储,最后再缝合。

from linked_list import LinkedList


class MyLinkedList(LinkedList):

    def partition(self, data):
        if self.head is None:
            return
        left=MyLinkedList(None)//创建左分区(小于data)的链表
        right=MyLinkedList(None)//创建右分区(大于等于data)的链表
        curr=self.head
        while curr is not None:
            if curr.data<data:
                left.append(curr.data)
            elif curr.data==data:
                right.insert_to_front(curr.data)//利用现成的前插方法把相等值前插入右链表
            else:
                right.append(curr.data)
            curr=curr.next
        curr_left=left.head
        if curr_left is None://对于开头(左边第一个),总要进行是否为空类型的判断
            return right
        else:
            while curr_left.next is not None:
                curr_left=curr_left.next//遍历到做链表末尾
            curr_left.next=right.head//首尾衔接
            return left
        

014对链表值进行求和

实现一个算法来对链表中结点的元素值进行求和。要求如下:

  • 数字以相反的顺序存储在链表中,如数字 37 在链表中存储的方式是,第 1 个结点为数字 7 ,第 2 个结点为数字 3 。
  • 求和是把两个链表的数字求和后,以相反的顺序存储在链表中。例如第一个链表的数字是 37,即输入为 7 -> 3,第二个链表输入为 2 -> 8,则输出链表为 9 -> 1 -> 1

挑战内容

本次挑战中,你需要在 reverse.py 文件中补充函数 add_reverse 的空缺部分。

  • MyLinkedList 类继承“实现链表类”挑战中的 LinkedList 类。
  • MyLinkedList 类的 add_reverse 方法用于对链表数字进行求和,参数 first_list 用于指定传入的第一个链表,参数 second_list 用于指定传入的第二个链表,它返回一个链表。
  • 如果传入链表中有 None,则返回 None

 代码:经典加法进位处理方法

from linked_list import LinkedList,Node//导入链表类继承,导入节点类生成新链表的头结点


class MyLinkedList(LinkedList):

    def add_reverse(self, first_list, second_list)://算出头结点,生成新链表
        if first_list is None or second_list is None:
            return None
        head=self._add_reverse(first_list.head,second_list.head,0)
        return MyLinkedList(head)

    def _add_reverse(self,first_node,second_node,carry)://由于相反顺序,第一个节点对应个位,相对应的节点存储的数字可以直接相加;carry用于进位使用,初始时为0
        if first_node is None and second_node is None and not carry://仅当节点均为空类型且无进位时返回空类型
            return None
        value=carry
        value+=first_node.data if first_node is not None else 0
        value+=second_node.data if second_node is not None else 0
        carry=1 if value>=10 else 0
        value%=10
        node=Node(value)//生成含有当前值的节点
        node.next=self._add_reverse(
            first_node.next if first_node is not None else None,
            second_node.next if first_node is not None else None,
            carry)//递归,把下一个节点算出,需要保证当前两个链表的节点不为空类型;当下一个为None通过return None跳出递归
        return node

015寻找链表循环的起点 

对于有循环的链表,实现一个算法来寻找链表循环的起点。要求如下:

  • 例如链表以第 2,3,4 个结点为循环,即结点链接顺序为 head -> 1 -> 2 -> 3 -> 4 -> 2 -> 3 -> 4 -> ··· ,需要返回第 2 个结点。

挑战内容

本次挑战中,你需要在 loop_start.py 文件中补充函数 find_loop_start 的空缺部分。

  • MyLinkedList 类继承“实现链表类”挑战中的 LinkedList 类。
  • MyLinkedList 类的 find_loop_start 方法用于寻找链表循环的起点,它没有输入值,需要返回一个结点。
  • 如果链表没有结点,则返回 None;如果链表中没有循环,也返回 None

 思路:快慢双指针判断是否有环;同步双指针移动到循环起始点;

原理图: 

代码:最后一个注释是疑问

from linked_list import LinkedList


class MyLinkedList(LinkedList):

    def find_loop_start(self):
        if self.head is None or self.head.next is None:
            return None
        slow=self.head
        fast=self.head
        while fast.next is not None:
            slow=slow.next
            fast=fast.next.next//快指针比慢指针多出一倍距离
            if fast is None://如果没有环,快慢不相等,最终快指针指向空类型
                return None
            if slow==fast://当这个一倍距离通过环抵消,快慢指针才会相等
                break
        slow=self.head
        while slow!=fast:
            slow=slow.next
            fast=fast.next
            if fast is None://暂时不理解之处,为何进入环了还要判断是否为空类型?
                return None
        return slow

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值