链表
链表 - Day1
val 为节点值,next 为节点 listnode
创建虚拟节点 会方便删除等操作 dummy = listnode[next = head]
class ListNode:
def __init__(self, val, next = None):
self.val = val
self.next = next
## self调用实例,例如data.min()前面的即为实例
创建装饰器(本质上是一个高阶函数,它接受一个函数作为参数,并返回一个新的函数,可以使函数每次都连带执行)
@staticmethod:将方法定义为静态方法,不需要传递 self 参数。
@classmethod:将方法定义为类方法,第一个参数是类对象 cls。
@property:将方法转换为属性,可以通过访问属性的方式调用方法。
from typing import Optional, List
class ListNode:
def __init__(self, val, next = None):
self.val = val
self.next = next
# 辅助函数: 将列表转换成链表
def list_to_linkedlist(elements: List[int]) -> Optional[ListNode]:
dummy_head = ListNode()
current = dummy_head
for element in elements:
current.next = ListNode(val=element)
current = current.next
return dummy_head.next
# 辅助函数: 将链表转换成列表
def linkedlist_to_list(head: Optional[ListNode]) -> List[int]:
elements = []
current = head
while current:
elements.append(current.val)
current = current.next
return elements
# 装饰器: 转换输入和输出
def convert_input_output(func):
def wrapper(self, head_list: List[int], val: int) -> List[int]:
head = list_to_linkedlist(head_list) # 将列表转换成链表
new_head = func(self, head, val) # 调用原函数
result_list = linkedlist_to_list(new_head) # 将结果链表转换回列表
return result_list
return wrapper
203.移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
主要在于加虚拟节点,然后依次遍历
class Solution:
@convert_input_output
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummy_head = ListNode(next = head) # 创建虚拟头部节点以简化删除过程
current = dummy_head # 遍历列表并删除值为val的节点
while current.next:
if current.next.val == val:
current.next = current.next.next
else:
current = current.next
return dummy_head.next
707.设计链表的五个接口
获取链表第index个节点的数值
在链表的最前面插入一个节点
在链表的最后面插入一个节点
在链表第index个节点前面插入一个节点
删除链表的第index个节点
class MyLinkedList:
def __init__(self):
self.dummy_head = ListNode()
self.size = 0
def get(self, index: int) -> int:
current = self.dummy_head
if index >= 0 and index <= self.size:
for i in range(index):
current = current.next
return current.val
else:
return -1
def addAtHead(self, val: int) -> None:
new_head = ListNode(val, self.dummy_head.next)
self.size += 1
def addAtTail(self, val: int) -> None:
current = self.dummy_head
while current.next:
current = current.next
current.next = ListNode(val)
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
current = self.dummy_head
if index >= 0 and index <= self.size:
for i in range(index-1):
current = current.next
new_node = ListNode(val, current.next)
current.next = new_node
else:
return
self.size += 1
def deleteAtIndex(self, index: int) -> None:
current = self.dummy_head
if index >= 0 and index <= self.size:
for i in range(index - 1):
current = current.next
current.next = current.next.next
else:
return
self.size -= 1
链表 - Day2
206.反转链表
双指针,类似数组,但要注意的是需要增加临时节点存储原链表下一节点,否则链表转向后会断开无法继续循环
class Solution:
@convert_input_output
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head
pre = None # 不可以用listnode(),会使得结果增加一个节点
while cur:
tmp = cur.next # 存储下一节点,为了遍历节点
cur.next = pre # 反转方向
pre = cur # 更新 新链表
cur = tmp # 遍历原方向下一个节点
return pre
24.两两交换链表中的节点
需要递归,循环内交换前后两个节点,前节点向后连接时递归后面的节点
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
pre = head
cur = head.next
next = head.next.next
cur.next = pre # 后节点连接前节点
pre.next = self.swapPairs(next) # 前节点连接后后节点,该节点需更新,递归
return cur
19.删除链表的倒数第 N 个结点
好牛逼的思路,快指针先走n+1步,剩下走的路就是慢指针需要走的路,就可以找到倒数n的节点位置
class Solution:
@convert_input_output
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(next = head)
slow = fast = dummy
for i in range(n+1):
fast = fast.next
while fast:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy.next
面试题 02.07. 链表相交
重点在于对齐,因为如果相交,后续节点长度相等,只要从短的一条链同步进行即可,从后往前判断不现实
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
lenA = 0
lenB = 0
curA = headA
curB = headB
while curA: # 计算长度
lenA += 1
curA = curA.next
while curB:
lenB += 1
curB = curB.next
curA = headA # 重置,并排序
curB = headB
if lenA > lenB:
curA, curB = curB, curA
lenA, lenB = lenB, lenA
for i in range(lenB - lenA): # 长度对齐
curB = curB.next
while curA:
if curA == curB:
return curA
curA = curA.next
curB = curB.next
return None
142.环形链表 II
快的走两步,慢的走一步,环形的话一定会相遇,相遇时重置慢指针
2(x+y) = x+n(y+z)+y
x+y = n(y+z) 原地走n圈
x = n(y+z)-y 即回到相遇点
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = head
fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
slow = head
while slow != fast:
slow = slow.next
fast = fast.next
return slow
return None

查看10道真题和解析