链表
目录
链表基础知识
- 定义:链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,数据域和指针域,最后一个节点的指针域指向None(空指针的意思)。
链表的入口节点称为链表的头结点也就是head - 分类:单链表、双链表、循环链表
203 移除链表元素
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummy = ListNode(0,head) # 哑结点
p = dummy # 指针
while p.next != None: # 只要下一个不为空则一直进行
if p.next.val == val: # 下一个的val等于目标值
p.next = p.next.next # 通过对next赋值实现删除元素
else: # 下一个的val不等于目标值:指针移动
p = p.next
return dummy.next
707 设计链表
class MyLinkedList:
def __init__(self): # 列表需要虚拟头结点和链表长度(不包括虚拟结点)
self.head = ListNode() # 设置虚拟头结点
self.size = 0 # 列表长度
def get(self, index: int) -> int:
if index<0 or index>=self.size:
return -1
cur = self.head
for _ in range(index+1):
cur = cur.next
return cur.val
def addAtHead(self, val: int) -> None:
new = ListNode(val,self.head.next)
self.head.next = new
self.size += 1 # 注意改变size
'''
i = self.head # 用于debug 输出链表
while i != None:
print(i.val)
i = i.next
'''
def addAtTail(self, val: int) -> None:
cur = self.head
while cur.next: # 若下一个指向空 则终止 进行添加
cur = cur.next
cur.next = ListNode(val)
self.size += 1
def addAtIndex(self, index: int, val: int) -> None:
if index<=0:
self.addAtHead(val)
elif index==self.size:
self.addAtTail(val)
elif index>0 and index<self.size:
cur = self.head
for _ in range(index):
cur = cur.next
temp = cur.next
cur.next = ListNode(val,temp)
self.size += 1
def deleteAtIndex(self, index: int) -> None:
if index>=0 and index<self.size:
cur = self.head
for _ in range(index):
cur = cur.next
cur.next = cur.next.next
self.size -= 1
class ListNode:
def __init__(self,val=0,next=None):
self.val = val
self.next = next
206 反转链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
pre = None
cur = head
while cur: # 快指针非空
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
24 两两交换链表中的节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0,head)
temp = dummy
while temp.next != None and temp.next.next!=None:
node1 = temp.next
node2 = temp.next.next
temp.next = node2
node1.next = node2.next
node2.next = node1
temp = node1
return dummy.next
19 删除链表的倒数第 N 个结点
# 双指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(0,head)
s = f = dummy
for _ in range(n):
f = f.next # 提前走n步
while f.next!=None:
s = s.next
f = f.next
s.next = s.next.next
return dummy.next
160 相交链表
# 双指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
a = headA
b =headB
while a or b: # 都为空则结束
if a==b:
return a
if a: # a没到末端
a = a.next
else:
a = headB
if b: # b没到末端
b = b.next
else:
b = headA
return
142 环形链表Ⅱ
分析:快慢指针
# 快慢指针
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0,head)
s = f = dummy
while f.next != None and f.next.next != None:
f = f.next.next
s = s.next
if f == s:
s = dummy
while s != f:
s = s.next
f = f.next
return s
return
146. LRU 缓存(双链表结合哈希表)
分析:
class DLinkedNode:
def __init__(self, key = 0, value = 0):
self.key = key # 为了能在哈希表中找到链表中被删除的节点
self.value = value
self.pre = None # 双向链表 无需遍历就可以找到当前节点的前一个结点地址
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.head = DLinkedNode()
self.tail = DLinkedNode()
self.head.next = self.tail
self.tail.pre = self.head
self.hp = {} # 初始化一个哈希表
self.capacity = capacity
self.size = 0
def get(self, key: int) -> int:
if key not in self.hp:
return -1
node = self.hp[key]
self.moveToHead(node)
return node.value
def put(self, key: int, value: int) -> None:
if key in self.hp:
node = self.hp[key]
self.moveToHead(node)
node.value = value
else:
node = DLinkedNode(key, value)
self.hp[key] = node
self.addToHead(node)
self.size += 1
if self.size>self.capacity:
removedTail = self.removeTail()
del self.hp[removedTail.key] # 只有节点有属性key才能从字典中找到并删除
self.size -= 1
def moveNode(self, node):
node.pre.next = node.next
node.next.pre = node.pre
def moveToHead(self, node): # 将节点移到头部等于先将节点移除,再将节点添加到头部
self.moveNode(node)
self.addToHead(node)
def addToHead(self, node):
headnext = self.head.next
self.head.next = node
node.next = headnext
node.pre = self.head
headnext.pre = node
def removeTail(self):
node = self.tail.pre
'''
node.pre.next = self.tail
self.tail.pre = node.pre
'''
self.moveNode(node)
return node
23. 合并K个升序链表
思路:两两合并 注意对奇偶的讨论和哑结点的加入
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
def merge2Lists(l1, l2):
dummyhead = ListNode(0)
cur = dummyhead
while l1 and l2: # 链表非空
if l1.val <= l2.val:
cur.next = l1
cur = l1 # 当前指针移动
l1 = l1.next # l1移动
else:
cur.next = l2
cur = l2
l2 = l2.next
if not l1: # l1 为空
cur.next = l2
else:
cur.next = l1
return dummyhead.next
n = len(lists)
temp = []
if n == 0:
return
if n == 1:
return lists[0] # 返回地址 不能直接返回lists
if n == 2:
return merge2Lists(lists[0], lists[1])
for i in range(0, n, 2):
if i == n-1: # 说明n为奇数
temp.append(lists[i])
else:
temp.append(merge2Lists(lists[i], lists[i+1]))
return self.mergeKLists(temp)
# 时O(kn×logk) 其中n是单个链表长度,k是链表数目,(每次合并两个链表,以第一次合并为例,合并两链表时间为O(2n),总共进行k/2次,所以为O(nk)
# 空O(logk) 递归深度