返回
算法巧解:数组与链表双管齐下,搞定连续中值
前端
2023-09-30 22:51:43
连续中值算法详解:数组与链表双解法
在数据流分析和滑动窗口算法等场景中,连续中值计算至关重要。它可以实时反映数据流中值的变化趋势。本文将深入解析两种经典的连续中值算法:数组解法和链表解法,助你轻松掌握这道面试难题。
数组解法
原理:
数组解法利用排序数组的特性。每次新值插入时,通过二分法查找插入位置,保持数组有序。这样,数组中位数指针始终指向中值元素。
算法步骤:
- 初始化一个有序数组
arr
。 - 当收到新值
x
时:- 采用二分法查找
x
在arr
中的插入位置idx
。 - 将
x
插入arr
中的idx
位置。
- 采用二分法查找
- 计算并返回数组
arr
的中值。
优缺点:
- 插入和查找操作高效。
- 删除操作较慢,需要重新排序数组。
代码示例:
import bisect
class Solution:
def __init__(self):
self.arr = []
def insert(self, x):
idx = bisect.bisect_left(self.arr, x)
self.arr.insert(idx, x)
def get_median(self):
n = len(self.arr)
if n % 2 == 0:
return (self.arr[n // 2] + self.arr[n // 2 - 1]) / 2
else:
return self.arr[n // 2]
链表解法
原理:
链表解法使用双向链表,并维护一个中位数指针 mid
。每次新值插入时,遍历链表找到合适位置插入,并更新 mid
指针指向中值元素。
算法步骤:
- 初始化一个双向链表
lst
和中位数指针mid
。 - 当收到新值
x
时:- 遍历链表,找到第一个大于等于
x
的节点node
。 - 如果
node
为空,则将x
插入链表尾部。 - 否则,将
x
插入node
之前。
- 遍历链表,找到第一个大于等于
- 更新中位数指针
mid
:- 如果链表长度为奇数,则
mid
指向中间节点。 - 如果链表长度为偶数,则
mid
指向两个中间节点的左侧节点。
- 如果链表长度为奇数,则
- 返回
mid
节点的值作为中值。
优缺点:
- 插入和删除操作高效。
- 查找操作较慢,需要遍历链表。
代码示例:
class Node:
def __init__(self, val):
self.val = val
self.prev = None
self.next = None
class Solution:
def __init__(self):
self.head = Node(float('inf'))
self.tail = Node(float('inf'))
self.head.next = self.tail
self.tail.prev = self.head
self.mid = self.head
def insert(self, x):
node = self.head
while node.next.val < x:
node = node.next
new_node = Node(x)
new_node.next = node.next
node.next = new_node
new_node.prev = node
new_node.next.prev = new_node
self.update_mid()
def update_mid(self):
n = self.get_length()
if n % 2 == 1:
self.mid = self.head.next
else:
self.mid = self.mid.next
def get_length(self):
node = self.head.next
length = 0
while node != self.tail:
length += 1
node = node.next
return length
def get_median(self):
return self.mid.val
总结
数组解法和链表解法各有其特点:
- 数组解法插入和查找高效,适合数据量较大且需要频繁查找中值的情况。
- 链表解法插入和删除高效,适合数据流不断变化且需要频繁更新中值的情况。
根据实际场景需求,选择最合适的解法至关重要。
常见问题解答
-
数组解法的时间复杂度是多少?
- 二分查找插入时间复杂度为 O(log n),因此整体时间复杂度为 O(n log n)。
-
链表解法的时间复杂度是多少?
- 遍历链表和更新中位数指针时间复杂度为 O(n),因此整体时间复杂度为 O(n)。
-
哪种解法更节省空间?
- 数组解法通常需要更多空间来存储排序数组,而链表解法只需要存储节点指针,因此链表解法更节省空间。
-
哪种解法在并行处理方面更有效?
- 数组解法适合并行处理,因为可以将数组划分为多个子数组并同时处理。链表解法难以并行处理,因为更新中位数指针需要对整个链表进行遍历。
-
是否还有其他连续中值算法?
- 除数组和链表解法外,还有其他算法,如堆、分治和滚动中值,各有其优缺点和适用场景。