链表基础知识
python定义:
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
删除节点:
添加节点:
性能分析:
移除链表元素
在这里插入代码片
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
dummy_head = ListNode(next=head)
cur = dummy_head
while cur.next:
if cur.next.val == val:
cur.next = cur.next.next
else:
cur = cur.next
return dummy_head.next
设计链表
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- -addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
相当于啥也没给你,全在里面操作。
class ListNode: # 单链表
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class MyLinkedList:
def __init__(self):
self.dummy_head = ListNode() # 虚拟头
self.count = 0 # 节点数
def get(self, index: int) -> int:
if 0 <= index < self.count:
cur = self.dummy_head
for i in range(index + 1):
cur = cur.next
return cur.val
else:
return -1
def addAtHead(self, val: int) -> None:
new_list = ListNode(val)
new_list.next = self.asummy_head.next
self.dummy_head.next = new_list
self.count += 1
def addAtTail(self, val: int) -> None:
new_list = ListNode(val)
cur = self.dummy_head
while cur.next:
cur = cur.next
cur.next = new_list
self.count += 1
def addAtIndex(self, index: int, val: int) -> None:
if index < 0:
self.addAtHead(val)
elif 0 <= index < self.count:
new_list = ListNode(val)
cur = self.dummy_head
for i in range(index):
cur = cur.next
new_list.next = cur.next
cur.next = new_list
self.count += 1
elif index == self.count:
self.addAtTail(val)
def deleteAtIndex(self, index: int) -> None:
if 0 <= index < self.count:
cur = self.dummy_head
for i in range(index):
cur = cur.next
cur.next = cur.next.next
self.count -= 1
双链表增加了获取index 和直接增加节点的功能。
class LinkNode: # 双链表
def __init__(self, val = 0, prev = None, next = None):
self.prev = prev
self.next = next
self.val = val
class MyLinkedList:
def __init__(self):
self.dummy_head = LinkNode()
self.dummy_tail = LinkNode()
self.dummy_head.next, self.dummy_tail.prev = self.dummy_tail, self.dummy_head
self.count = 0
def get_node(self, index):
if index < self.count // 2:
cur = self.dummy_head
for i in range(index + 1):
cur = cur.next
return cur
else:
cur = self.dummy_tail
for i in range(self.count - index):
cur = cur.prev
return cur
def get(self, index: int) -> int:
if 0 <= index < self.count:
node = self.get_node(index)
return node.val
else:
return -1
def addAtHead(self, val: int) -> None:
self.add_data(val, self.dummy_head, self.dummy_head.next)
def addAtTail(self, val: int) -> None:
self.add_data(val, self.asummy_tail.prev, self.dummy_tail)
def addAtIndex(self, index: int, val: int) -> None:
if index <= 0:
self.add_data(val, self.dummy_head, self.dummy_head.next)
elif self.count < index:
return
elif 0 < index < self.count:
node = self.get_node(index)
self.add_data(val, node.prev, node)
elif index == self.count:
self.add_data(val, self.dummy_tail.prev, self.dummy_tail)
def add_data(self, val, prev_node, next_node):
new_node = LinkNode(val)
prev_node.next, next_node.prev = new_node, new_node
new_node.prev, new_node.next = prev_node, next_node
self.count += 1
def deleteAtIndex(self, index: int) -> None:
if 0 <= index < self.count:
node = self.get_node(index)
node.prev.next, node.next.prev = node.next, node.prev
self.count -= 1
翻转链表
pre = cur 这一步相当于把pre移到cur的位置,原来的节点保持不变
class Solution: # 迭代
def reverseList(self, head: ListNode) -> ListNode:
cur = head
pre = None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
删除链表的倒数第N个节点
- 定义fast指针和slow指针,初始值为虚拟头结点
- fast首先走n + 1步 ,为什么是n+1呢,因为只有这样同时移动的时候slow才能指向删除节点的上一个节点(方便做删除操作)
- fast和slow同时移动,直到fast指向末尾
- 删除slow指向的下一个节点
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
self.dummy_head = ListNode()
self.dummy_head.next = head
slow, fast = self.dummy_head, self.dummy_head
for i in range(n+1):
fast = fast.next
while fast:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
# Tip: 这里要返回self.dummy_head.next,而不是返回head,因为当链表的长度只有1并且删除倒数第一个时head还是存在的。
return self.dummy_head.next
链表相交
即球两个链表交点节点的指针,注意这里交点不是数值相同,而是指针相同。
方法:求出两个链表的长度,并求出两个链表长度的差值,然后让curA移动到和curB末尾对齐的位置,如图:
比较curA和curB是否相同,如果不相同吗,同时往后移动,如果遇到curA==curB则为碰到交点,否则循环退出返回空指针。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
curA = headA
curB = headB
def get_lens(head):
count = 0
while head:
count += 1
head = head.next
return count
len_A = get_lens(headA)
len_B = get_lens(headB)
if len_A > len_B:
for i in range(len_A - len_B):
curA = curA.next
else:
for i in range(len_B - len_A):
curB = curB.next
while curA:
if curA == curB:
return curB
curA = curA.next
curB = curB.next
return None
环形链表
- 判断是否由环
定义fast和slow指针,从头结点出发,fast指针每次移动两个节点,slow每次移动一个节点,如果有环,就一定会相遇。 - 如果有环,如何找到这个环的入口
见代码随想录:index_x从x出发后,从slow和fast交点出发的点index_z一定会和x相遇在环形的起始点
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
curA = head
curB = slow
while curA != curB:
curA = curA.next
curB = curB.next
return curA
return None
感谢阅读