python | 算法-链表结构、反转、公共部分、回文结构、按值划分
针对b站视频左神算法与数据结构,自己练习对应的python代码
相关链接:
1️⃣b站视频地址
2️⃣视频笔记(其实主要是题目截图)
链表
一、链表结构
节点结构:
# 链表的基本结构--节点
class Node:
def __init__(self, cargo=None, next=None):
self.cargo = cargo
self.next = next
def __str__(self):
#测试基本功能输出字符串
return str(self.cargo)
print(Node(5))
# 输出5
链表结构和基本运算:
class Node():
"""
链表的基本结构--节点
"""
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def __str__(self):
return str(self.data)
class LinkedList():
"""
链表结构及基本操作
"""
def __init__(self, head=None):
self.head = head
def __len__(self):
#功能:给定头节点返回链表的长度
cur = self.head
res = 0
while cur is not None:
res += 1
cur = cur.next
return res
def insertFront(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
cur = self.head
while cur.next is not None:
cur = cur.next
cur.next = node
return node
def find(self, data):
#功能:查找数值等于data的节点
if data is None:
return None
cur = self.head
while cur is not None:
if cur.data == data:
return cur
return None
def delete(self, data):
#功能:删除链表中数值等于data的节点
if data is None: return
if self.head is None: return
if self.head.data == data:
self.head = self.head.next
return
pre_node = self.head
cur_node = self.head.next
while cur_node is not None:
if cur_node.data == data:
pre_node.next = cur_node.next
else:
pre_node = cur_node
cur_node = cur_node.next
def deleteAlt(self, data):
#功能:删除节点方法2
if data is None: return
if self.head is None: return
if self.head.data == data:
self.head = self.head.next
return
pre_node = self.head
while pre_node.next is not None:
if pre_node.next.data == data:
pre_node.next = pre_node.next.next
pre_node = pre_node.next
二、反转单向和双向链表
Q1:分别实现反转单向链表和反转双向链表的函数
req:如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度为O(1)
#反转单向链表
class Node():
def __init__(self, data=None, next=None):
self.data = data
self.next = next
class LinkedList():
def __init__(self, head=None):
self.head = head
def reverseList(self):
if self.head.next is None: return
cur_node = self.head.next
self.head.next = None
cur_next = cur_node.next
cur_node.next = self.head
self.head = cur_node
while cur_next is not None:
cur_node = cur_next
cur_next = cur_node.next
cur_node.next = self.head
self.head = cur_node
#双向链表的反转
class Node():
def __init__(self, data=None, last=None, next=None):
self.data = data
self.last = last
self.next = next
class duLinkedList():
def __init__(self, head=None):
self.head = head
def reverse(self):
pre_node = self.head.last
while self.head.next is not None:
next_node = self.head.next
self.head.next = pre_node
self.head.last = next_node
pre_node = self.head
self.head = next_node
self.head.next = pre_node
self.head.last = None
三、打印两个有序链表的公共部分
#打印两个 有序 链表 的公共部分
class Node():
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def Len(head):
res = 0
while head:
res += 1
head = head.next
return res
def iseq(node1, node2):
return node1.data == node2.data and node1.next == node2.next and id(node1) == id(node2)
def ComPart(head1, head2):
len1, len2 = Len(head1), Len(head2)
p1 = head1 if len1 > len2 else head2
for i in range(abs(len1-len2)):
p1 = p1.next
p2 = head2 if len1 > len2 else head1
while p1:
if iseq(p1, p2):
print(p1.data)
p1 = p1.next
p2 = p2.next
if __name__ == '__main__':
head1 = Node(1)
n2 = Node(2)
n3 = Node(2)
n4 = Node(3)
n5 = Node(3)
n6 = Node(4)
head2 = Node(2)
n7 = Node(3)
head1.next = n2
n2.next = n3
n3.next = n4
n4.next = n5
n5.next = n6
head2.next = n7
n7.next = n4
ComPart(head1, head2)
# 输出 3, 3, 4
四、判断一个链表是否为回文结构
补充知识:Python用列表实现堆栈
#判断一个链表是否为回文结构
class Node():
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def isPalindrome1(head):
"""
function 1 -> space=O(N)
:param head: Node
:return: bool
"""
if head is None or head.next is None:
return True
# step1 all nodes put in the stack
stack = []
p = head
while p is not None:
stack.append(p.data)
p = p.next
# step2 out stack and compare
while len(stack):
if stack.pop() != head.data:
return False
head = head.next
return True
def isPalindrome2(head):
"""
function2 -> space=O(1)
:param head: Node
:return: bool
"""
if head is None or head.next is None:
return True
# step1 find mid node
n1, n2 = head, head
while n2.next is not None and n2.next.next is not None:
n1 = n1.next # n1 -> mid
n2 = n2.next.next # n2 -> end
n2 = n1.next # n2 -> right first node
n1.next = None # mid.next -> None
# step2 reverse right part
while n2 is not None:
tmp = n2.next # tmp -> save next node
n2.next = n1 # n2.next connect mid
n1 = n2 # n1 -> save pre node
n2 = tmp # n2 move
# now n1 is last node
tmp = n1 # tmp -> save last node
n2 = head
# step3 check palindrome
res = True
while n1 is not None and n2 is not None:
if n1.data != n2.data:
res = False
break
n1 = n1.next
n2 = n2.next
# step4 recover list
n1 = tmp.next # tmp -> last node
tmp.next = None
while n1 is not None:
n2 = n1.next # n2 -> save next node
n1.next = tmp # reverse
tmp = n1 # tmp -> save pre node
n1 = n2 # n1 move
return res
五、单链表按值划分
# 单链表划分
class Node():
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def ListPartition(head, pivot):
"""
Partition a linkedlist into left less-than, mid equal and right more-than pivot
:param head:Node
:param pivot:int
:return:Node
"""
if head is None or head.next is None:
return head
cur, p1, p2, p3 = head, None, None, None
# partiton into three parts: less, equal, more
while cur is not None:
lat = cur.next
if cur.data < pivot:
if p1 is None:
p1_tail = cur # tail of less-than part
cur.next = p1
p1 = cur # p1 -> head node of less-than part
elif cur.data == pivot:
if p2 is None:
p2_tail = cur # tail of equal part
cur.next = p2
p2 = cur # p2 -> head of equal part
else:
cur.next = p3
p3 = cur # p3 -> head of more-than part
cur = lat # cur move
# connect three parts
if p1 is None:
if p2 is None:
return p3
else:
p2_tail.next = p3
return p2
elif p2 is None:
p1_tail.next = p3
return p1
elif p3 is None:
p1_tail.next = p2
return p1
else:
p1_tail.next = p2
p2_tail.next = p3
return p1
p1_tail.next = p2
p2_tail.next = p3
return p1
🤔上面代码没有完成进阶要求:保持各部分原本的相对顺序
(上面代码用的每个部分都用的头插法,所以最后每部分顺序刚好与原来顺序相反,改成尾插法就可以保持相对顺序了)
并且后面整合三个部分的代码不够优雅简洁
优雅的代码还得左神,看了视频里左神的代码,我又优化了一遍:
# 单链表划分
# Time:O(N)
# Space:O(1)
class Node():
def __init__(self, data=None, next=None):
self.data = data
self.next = next
def ListPartition(head, pivot):
sh = None # small head
st = None # small tail
eh = None # equal head
et = None # equal tail
mh = None # big head
mt = None # big tail
# step1 partition according to small, equal and big
while head is not None:
next = head.next # next -> save next node
head.next = None # head -> current node
if head.data < pivot:
if sh is None: # firt small node
sh = head
st = head
else:
st.next = head # connect to tail node
st = head # tail node move
elif head.data == pivot:
if eh is None: # first equal node
eh = head
et = head
else:
et.next = head
et = head
else:
if mh is None: # first big node
mh = head
mt = head
else:
mt.next = head
mt = head
head = next # current node move
# step2 connect all parts
if sh is not None:
st.next = eh
et = et if eh is not None else st # et -> connect to mh
if et is not None: # have small or equal
et.next = mh
return sh if sh is not None else (eh if eh is not None else mh)