[英]Most optimal way of writing sparse array not using any libraries nor hash table
給定一個大數組,其中絕大多數元素為零。 創建一個 class 可以更有效地存儲這些元素的空間。 你的class必須有以下方法:
constructor(originalArr)
- 你傳入原始數組來存儲set(i, val)
- 在索引 i 處設置值 valget(i)
- 獲取索引 i 處的值想出一個不使用字典/hash 表的數據結構。
EXAMPLE(S) sparseArr = new SparseArray([0, 0, 1, 0, 0, 0, 0, 2]) sparseArr.get(0) // returns 0 sparseArr.set(0, 3) sparseArr.get(0) // returns 3 sparseArr.get(2) // returns 1 FUNCTION SIGNATURE class SparseArray: constructor(original) set(i, val) get(i)
我正在考慮擁有三個 arrays、non_zero_arr、non_zero_indices_arr 和 zero_indices_arr 但是當我想到將零值設置為非零的情況時,我會在 zero_indices_arr 中使用二進制搜索來查找給定索引是否存在於 zero_indices_arr 中,刪除數組中的索引(使用數組切片?)再次通過二進制搜索在non_zero_indices_arr中找到position,然后使用數組切片添加放置新的更新索引並使用其在non_zero_indices_arr中的索引通過使用數組更新其在non_zero_arr中的non_zero_value再次切片。
我想每個操作的時間復雜度是
構造函數的 O(n) [用於在適當命名的數組中記錄索引、零和非零]
O(log n) for get [用於非零或零索引數組中的二進制搜索索引]
O(log n + n) [搜索然后切片數組並可能添加更新值]
但對我來說,這感覺有點混亂或堅韌不拔。 有沒有更優化更清潔的方法來做到這一點? 鑒於這是一個面試問題? 請隨時糾正我的思路或提出您的最佳解決方案和時間復雜度。
先感謝您
有很多數據結構可以處理這些需求,包括:
另一個是按位 trie 。
這是一個准系統按位 trie 實現,其中每個節點只處理給定索引的一位,因此它是一棵二叉樹。 樹的高度將等於數據結構必須為其存儲值的最大索引的二進制表示中的位數。
class SparseArray:
def __init__(self, original=None):
self.height = self.tree = 0
if original:
for i, val in enumerate(original):
if val:
self.set(i, val)
def remove(self, i):
def recur(node, shift, i):
j = (i >> shift) & 1
node[j] = shift and recur(node[j], shift - 1, i & ((1 << shift) - 1))
return node if any(node) else 0
if i.bit_length() <= self.height:
self.tree = recur(self.tree, self.height - 1, i)
# Reduce height if possible
if self.tree != 0:
while self.height > 1 and self.tree[1] == 0:
self.height -= 1
self.tree = self.tree[0]
else:
self.height = 0
def set(self, i, val):
if val == 0: # We don't store zeroes...
return self.remove(i)
# Increase tree height if this index needs more bits
width = i.bit_length()
if self.height < width and self.tree != 0:
for _ in range(self.height, width):
self.tree = [self.tree, 0]
self.height = max(width, self.height)
# Drill down
if not self.tree:
self.tree = [0]*2
node = self.tree
for bit in range(self.height - 1, 0, -1):
side = (i >> bit) & 1
if node[side] == 0:
node[side] = [0]*2
node = node[side]
node[i & 1] = val # Set leaf's value
def get(self, i):
node = self.tree
if i.bit_length() > self.height: # Out of current range
return 0
node = self.tree
for bit in range(self.height - 1, 0, -1):
side = (i >> bit) & 1
node = node[side]
if node == 0: # No subtree here
return 0
return node[i & 1] # Get leaf's value
def items(self):
def recur(node, i):
if isinstance(node, list):
yield from recur(node[0], i*2)
yield from recur(node[1], i*2+1)
elif node != 0:
yield i, node
yield from recur(self.tree, 0)
最壞情況下的空間復雜度為 O(),其中 是存儲在稀疏數組中的非零值的個數, 是用於非零值的最大索引的二進制表示中的位數。 最壞情況的一個例子是所有索引都是 2 的連續冪。
最好的情況空間復雜度是 O()。 這是二叉樹完美的時候,這意味着數組中沒有間隙(它不是稀疏的)。
get
和set
的時間復雜度是O()。
當節點獲得更大的分支因子(而不是 2)並因此處理更大的位塊而不是 1 時,性能將會提高。比如 4 位。
存在幾種改進 memory 和速度的變體。 請參閱 bitmap 的按位樹,包括 CTPOP 位破解實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.