📌  相关文章
📜  空数组的最低成本,其中删除元素的成本为2 ^(removed_count)* arr [i](1)

📅  最后修改于: 2023-12-03 14:56:37.389000             🧑  作者: Mango

空数组的最低成本

如果我们要实现一个空数组,并且在其中进行元素的添加和删除,我们需要考虑数组的成本。在删除元素的情况下,通常我们需要将删除位置后的所有元素向前移动,这样稍大的数组规模就需要更多的成本。但是,如果我们有一个空数组,我们该如何最小化删除元素的成本呢?

答案是通过以指数级别降低删除元素的成本,并充分使用已经删除的元素所占空间。具体来说,我们可以通过将已删除元素的存储顺序打乱并关联每个元素的删除状态,来减少数组的规模和移动元素的次数。

代码实现如下:

class EmptyArray:
    def __init__(self):
        self._deleted_indices = []
        self._data = []

    def __getitem__(self, index):
        return self._data[index]

    def __setitem__(self, index, value):
        self._data[index] = value

    def __delitem__(self, index):
        self._deleted_indices.append(index)

    def __len__(self):
        return len(self._data) - len(self._deleted_indices)

    def get(self, index, default=None):
        try:
            return self._data[index]
        except IndexError:
            return default

    def __repr__(self):
        return f"<EmptyArray {self._data}>"

    def __str__(self):
        return str(self._data)

其中,我们使用 _deleted_indices 列表来追踪已删除元素的索引,使用 _data 列表来存储未删除的元素。这样,对于删除元素的操作,我们只需要将该元素的索引添加到 _deleted_indices 中,而不需要真正地将该元素从 _data 中删除。这样,我们可以充分利用 _data 已有的空间,而不会浪费删除元素的空间。

在随着删除元素的数量逐渐增加时,我们可以通过通过将已删除元素在 _data 中存储的位置打乱,来进一步减少数组的规模(即存储到废弃元素的空间中)。

class EmptyArray:
    ...
    
    def _compact(self):
        j = 0
        for i, value in enumerate(self._data):
            if i in self._deleted_indices:
                j += 1
            else:
                self._data[i - j] = value
        del self._data[len(self._data) - j:]
        self._deleted_indices = []

    def append(self, value):
        self._data.append(value)

    def pop(self, index=-1):
        if not self._deleted_indices:
            return self._data.pop(index)
        else:
            real_index = index
            if index < 0:
                real_index = len(self) + index
            if real_index >= len(self):
                raise IndexError("pop index out of range")
            if real_index < 0:
                raise IndexError("pop index out of range")
            for i, deleted_index in enumerate(sorted(self._deleted_indices)):
                if real_index <= deleted_index:
                    self._deleted_indices.remove(deleted_index)
                    return self._data[deleted_index]
                real_index += 1
            real_index -= len(self._deleted_indices)
            value = self._data[real_index]
            del self._data[real_index]
            return value

这里,我们定义了一个 _compact 方法来打乱 _data 中已删除元素所占空间的存储位置。对于 pop 方法,我们保证在被删除的元素中,存储在更靠前(即更小的索引)的位置的元素先被删除,以便在后续添加元素时,将尽可能多的空间留给放置新元素。

现在,我们已经实现了一个最大限度降低删除元素成本的空数组,可以从中学习并且引入适合的逻辑到自己的代码中。