目录
009实现链表类
挑战内容
010删除链表的重复项
挑战内容
011寻找链表倒数第 k+1 个结点
挑战内容
013对链表值进行分区
挑战内容
014对链表值进行求和
挑战内容
挑战内容
本文题目编译自 Donne Martin 的开源项目
实现链表的插入,增加,查找,删除,查看长度和打印的方法。链表的介绍如下:
本次挑战中,你需要在 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
实现一个算法来删除链表中数据元素重复的结点。要求如下:
本次挑战中,你需要在 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
实现一个算法来寻找离链表最后一个结点 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
实现一个算法来对链表中结点的元素值进行分区,使所有小于 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
实现一个算法来对链表中结点的元素值进行求和。要求如下:
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