如何用常數時間插入、刪除和獲取隨機元素

如何用常數時間插入、刪除和獲取隨機元素

作者:Grey

原文地址: 如何用常數時間插入、刪除和獲取隨機元素

題目鏈接

LeetCode 380. Insert Delete GetRandom O(1)

主要思路

因爲要三個操作都達到O(1)時間複雜度,所以,我們可以空間換時間,採用兩個哈希表來實現

Map<Integer,Integer> indexMap = new HashMap<>();
Map<Integer, Integer> valueMap = new HashMap<>();

這兩個哈希表用於存儲值和位置關係,比如,初始狀態下,兩個表都是空的,現在增加一個元素v,那麼我們就把這個元素放到0號位置上,在哈希表結構中,就做如下操作

indexMap.put(v,0);
valueMap.put(0,v);

接下來來了一個元素x,我們就把這個元素x放到1號位置上,在哈希表的結構中,做如下操作

indexMap.put(x, 1);
valueMap.put(1, x);

這樣,

通過indexMap就可以以時間複雜度O(1)找到某個元素是否存在

通過valueMap就可以以時間複雜度O(1)找到某個位置的元素是什麼。

同時,我們增加一個size變量來得到當前的元素一共有多少個,在我們調用getRandom()方法的時候,我們就可以通過

valueMap.get((int) (Math.random() * size));

O(1)的時間複雜度,獲取到隨機位置的一個值。

最後是remove方法,由於我們可以獲取到任何一個位置的值,同時也可以知道任何一個位置所代表的值是什麼,我們可以很方便在indexMapvalueMap中刪除掉對應的記錄,

但是,被刪除的位置就不是順序排列的(會有缺口),舉個例子,假設生成indexMapvalueMap如下

image

此時,如果要刪掉2位置上的元素,被刪除元素後的indexMapvalueMap如下

image

由於產生的缺口,就導致valueMap在隨機取數的時候,如果隨機的位置是缺口處,就無法拿到數據,所以,針對remove操作,我們每次操作完,都要把列表最後一個位置的數,去填補缺口,如上示例中,我們可以將4號位置的元素去填補空缺,填補後的indexMapvalueMap如下

image

保持表的順序排列。

注意:在remove操作中,我們雖然是刪除掉某個元素,並且用最後一個位置的元素去替換,但是我們的順序必須是先取最後一個元素,並且用最後一個元素去覆蓋要刪除位置的元素,這樣操作的目的是,防止刪除的元素就是最後一個元素,導致用最後元素填充位置的時候,報空指針異常。

完整代碼見

    class RandomizedSet {
        // 某個val在哪個位置
        private Map<Integer, Integer> indexMap;
        // 某個位置上的val是什麼
        private Map<Integer, Integer> valueMap;
        private int size;

        public RandomizedSet() {
            size = 0;
            indexMap = new HashMap<>();
            valueMap = new HashMap<>();
        }

        public boolean insert(int val) {
            if (!indexMap.containsKey(val)) {
                valueMap.put(size, val);
                indexMap.put(val, size++);
                return true;
            }
            return false;
        }

        public boolean remove(int val) {
            if (!indexMap.containsKey(val)) {
                return false;
            }
            size--;
            int removeIndex = indexMap.get(val);
            int lastValue = valueMap.get(size);
            valueMap.put(removeIndex, lastValue);
            indexMap.put(lastValue, removeIndex);
            indexMap.remove(val);
            valueMap.remove(size);
            return true;
        }

        public int getRandom() {
            return valueMap.get((int) (Math.random() * size));
        }
    }

更多

算法和數據結構筆記

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章