链表
单链表:链表是指通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域、一个是指针域(存放指向下一个节点指针),最后一个节点的指针域指向null(空指针)。
链表的入口节点称为链表的头节点,即head。
双链表:每一个节点有两个指针域,一个指向下一个节点,另一个指向上一个节点。
双链表既可以向前查询也可以向后查询。
循环列表:链表首尾相连。
链表的存储方式: 链表在内存中不是连续分布的,链表通过指针域的指针链接在内存中的各个节点。即链表散乱分布在内存中的某地址上。
链表定义:
class ListNode:
def __init__(self, val):
self.val = val
self.next = None
移除链表元素
删除链表中等于给定值 val 的所有节点。
# 输入:head = [1,2,6,3,4,5,6], val = 6
# 输出:[1,2,3,4,5]
def solution(head, val):
pre_head = ListNode(-1)
pre_head.next = head
pre = pre_head
while pre:
if pre.next and pre.next.val == val:
pre.next = pre.next.next
else:
pre = pre.next
return pre_head.next
反转链表
反转一个单链表。
示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
def solution(head):
pre = None
cur = head
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
输入: head = [1,2,3,4]
输出:[2,1,4,3]
def solution(head):
pre = ListNode(-1)
pre.next = head
res = pre
while pre.next and pre.next.next:
cur = pre.next
tmp = pre.next.next
cur.next = tmp.next
pre.next = tmp
tmp.next = cur
pre = pre.next.next
return res.next
删除链表的倒数第N个节点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
def solution(head, n):
pre = ListNode(0)
pre.next = head
slow, fast = pre, pre
for i in range(n):
fast = fast.next
while fast:
fast = fast.next
slow = slow.next
slow.next = slow.next.next
return pre.next
链表相交
给定两个(单向)链表,判定它们是否相交并返回交点。请注意相交的定义基于节点的引用,而不是基于节点的值。换句话说,如果一个链表的第k个节点与另一个链表的第j个节点是同一节点(引用完全相同),则这两个链表相交。
输入:listA = [4,1,8,4,5], listB = [5,0,1,8,4,5]
输出:Reference of the node with value = 8
def solution(heada, headb):
cur_a, cur_b = heada, headb
while cur_a != cur_b:
cur_a = cur_a.next if cur_a else headb
cur_b = cur_b.next if cur_b else heada
return cur_a
环形链表II
题意: 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
def solution(head):
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast:
p = head
q = slow
while p != q:
p = p.next
q = q.next
return p
return None
设计一个链表
在链表类中实现这些功能:
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):
self.val = val
self.next = None
class MyLinkedList:
def __init__(self):
self._head = ListNode(0)
self._count = 0
def get(self, index):
if 0 <= index < self._count:
node = self._head
for _ in range(index+1):
node = node.next
return node
else:
return -1
def addAHead(self, val):
self.addAIndex(0, val)
def addATail(self, val):
self.addAIndex(self._count, val)
def addAIndex(self, index, val):
if index < 0:
index = 0
elif index > self._count:
return
self._count += 1
add_node = ListNode(val)
pre_node, cur_node = None, self._head
for _ in range(index + 1):
pre_node, cur_node = cur_node, cur_node.next
else:
pre_node.next, add_node.next = add_node, cur_node
def delAIndex(self, index):
if 0 <= index < self.count:
self._count -= 1
pre_node, cur_node = None, self.head
for _ in range(index+1):
pre_node, cur_node = cur_node, cur_node.next
else:
pre_node, cur_node = cur_node.next, None
# 双链表
# 相对于单链表, Node新增了prev属性
class Node:
def __init__(self, val):
self.val = val
self.prev = None
self.next = None
class MyLinkedList:
def __init__(self):
self._head, self._tail = Node(0), Node(0) # 虚拟节点
self._head.next, self._tail.prev = self._tail, self._head
self._count = 0 # 添加的节点数
def _get_node(self, index: int) -> Node:
# 当index小于_count//2时, 使用_head查找更快, 反之_tail更快
if index >= self._count // 2:
# 使用prev往前找
node = self._tail
for _ in range(self._count - index):
node = node.prev
else:
# 使用next往后找
node = self._head
for _ in range(index + 1):
node = node.next
return node
def get(self, index: int) -> int:
"""
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
"""
if 0 <= index < self._count:
node = self._get_node(index)
return node.val
else:
return -1
def addAtHead(self, val: int) -> None:
"""
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
"""
self._update(self._head, self._head.next, val)
def addAtTail(self, val: int) -> None:
"""
Append a node of value val to the last element of the linked list.
"""
self._update(self._tail.prev, self._tail, val)
def addAtIndex(self, index: int, val: int) -> None:
"""
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
"""
if index < 0:
index = 0
elif index > self._count:
return
node = self._get_node(index)
self._update(node.prev, node, val)
def _update(self, prev: Node, next: Node, val: int) -> None:
"""
更新节点
:param prev: 相对于更新的前一个节点
:param next: 相对于更新的后一个节点
:param val: 要添加的节点值
"""
# 计数累加
self._count += 1
node = Node(val)
prev.next, next.prev = node, node
node.prev, node.next = prev, next
def deleteAtIndex(self, index: int) -> None:
"""
Delete the index-th node in the linked list, if the index is valid.
"""
if 0 <= index < self._count:
node = self._get_node(index)
# 计数-1
self._count -= 1
node.prev.next, node.next.prev = node.next, node.prev