链表理论基础
单向链表
双向链表
循环链表
链表的存储
- 数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。
- 链表是分散在内存中的节点,通过指针链接起来组成的数据结构
链表节点的定义
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
链表的操作
删除节点:O(1)
添加节点:O(1)
查找节点:O(n)
从头节点开始遍历,直到找到需要的下标或者数值
适用场景
适合频繁增删,较少查找的场景。
203. 移除链表元素
dummy_head
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
if head is None:
return head
dummy_head = ListNode(0, 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
原链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
if head is None:
return head
while head is not None and head.val == val:
head = head.next
cur = head
while cur is not None and cur.next:
if cur.next.val == val:
cur.next = cur.next.next
else:
cur = cur.next
return head
707. 设计链表
dummy_head + 单向链表
class Node:
def __init__(self, val=0, next=None):
self.val= val
self.next= next
class MyLinkedList:
def __init__(self):
# dummy_head
self.head= Node(0)
self.length= 0
# Time complexity: O(index)
def get(self, index: int) -> int:
if index < 0 or index > self.length - 1:
return -1
else:
cur= self.head
for i in range(index+1):
cur= cur.next
return cur.val
# Time complexity: O(1)
def addAtHead(self, val: int) -> None:
self.addAtIndex(0, val)
# Time complexity: O(N)
def addAtTail(self, val: int) -> None:
self.addAtIndex(self.length, val)
# Time complexity: O(index)
def addAtIndex(self, index: int, val: int) -> None:
if index < 0:
index= 0
elif index > self.length:
return
else:
cur= self.head
for _ in range(index):
cur= cur.next
new_node= Node(val, cur.next)
cur.next= new_node
self.length += 1
# Time complexity: O(index)
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index > self.length - 1:
return
else:
cur= self.head
for _ in range(index):
cur= cur.next
next_next_node= cur.next.next
cur.next= next_next_node
self.length -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
双向链表
class Node:
def __init__(self, val=0, prev=None, next=None):
self.val = val
self.next = next
self.prev = prev
class MyLinkedList:
def __init__(self):
self.head = Node(0)
self.tail = Node(0)
self.head.next = self.tail
self.tail.prev = self.head
self.length = 0
# Time complexity: O(min(k,N−k))
def get(self, index: int) -> int:
if index < 0 or index > self.length - 1:
return -1
else:
if index+1 <= self.length - index:
cur = self.head
for i in range(index+1):
cur = cur.next
else:
cur = self.tail
for i in range(self.length - index):
cur = cur.prev
return cur.val
# Time complexity: O(1)
def addAtHead(self, val: int) -> None:
new_node = Node(val, self.head, self.head.next)
self.head.next.prev = new_node
self.head.next = new_node
self.length += 1
# Time complexity: O(1)
def addAtTail(self, val: int) -> None:
new_node = Node(val, self.tail.prev, self.tail)
self.tail.prev.next = new_node
self.tail.prev = new_node
self.length += 1
# Time complexity: O(min(k,N−k))
def addAtIndex(self, index: int, val: int) -> None:
if index < 0:
index = 0
elif index > self.length:
return
else:
if index <= self.length - index + 1:
cur = self.head
for _ in range(index):
cur = cur.next
else:
cur = self.tail
for _ in range(self.length - index + 1):
cur = cur.prev
new_node = Node(val, cur, cur.next)
cur.next.prev = new_node
cur.next = new_node
self.length += 1
# Time complexity: O(min(k,N−k))
def deleteAtIndex(self, index: int) -> None:
if index < 0 or index > self.length - 1:
return
else:
if index <= self.length - index - 1:
cur = self.head
for _ in range(index):
cur = cur.next
next_next_node = cur.next.next
cur.next = next_next_node
next_next_node.prev = cur
else:
cur = self.tail
for _ in range(self.length - index - 1):
cur = cur.prev
prev_prev_node = cur.prev.prev
cur.prev = prev_prev_node
prev_prev_node.next = cur
self.length -= 1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
206. 反转链表
prev, cur双指针反转
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Time complexity: O(N)
# Space complexity: O(1)
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
prev = None
cur = head
while cur:
next_node = cur.next
cur.next = prev
prev = cur
cur = next_node
return prev
递归法
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# Time complexity: O(N)
# Space complexity: O(N)
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None or head.next is None:
return head
def reverse(prev, cur):
if cur is None:
return prev
next_node = cur.next
cur.next = prev
return reverse(cur, next_node)
return reverse(None, head)