1. 程式人生 > 實用技巧 >381. [雜湊表]O(1) 時間插入、刪除和獲取隨機元素 - 允許重複

381. [雜湊表]O(1) 時間插入、刪除和獲取隨機元素 - 允許重複

381. O(1) 時間插入、刪除和獲取隨機元素 - 允許重複

方法一:雜湊表

由於\(List\)無法直接在\(O(1)\)的時間複雜度查詢元素值,所以可以考慮\(List\)\(HashMap\)聯合使用,\(HashMap\)\(HashMap\)記錄值和索引。考慮到一個值不會有2個相同索引,並且在刪除交換等操作時需要對值得索引也進行刪除等操作,所以索引的部分只需要再額外使用一個\(Set\)完成插入、刪除數字的下標即可。

由於\(List\)只有在刪除尾元素時,才是以\(O(1)\)的時間複雜度完成的,做法可以是先把需要刪除的元素與最後一個元素交換,在刪除最後一個元素。具體實現如下。

// 執行用時: 14 ms , 在所有 Java 提交中擊敗了 91.73% 的使用者
// 記憶體消耗: 45.3 MB , 在所有 Java 提交中擊敗了 56.87% 的使用者

class RandomizedCollection {
    int n ;//當前集合大小
    HashMap<Integer,Set<Integer>>map;
    ArrayList<Integer>list;
    Random random;
    /** Initialize your data structure here. */
    public RandomizedCollection() {
        this.random = new Random();
        this.map = new HashMap();
        this.n = 0;
        this.list = new ArrayList<>();
    }
    
    /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
    public boolean insert(int val) {
        Set set = map.get(val);
        if(set==null)   set = new HashSet<>();
        set.add(n);//新增索引
        list.add(val);
        map.put(val, set);
        n++;
        return set.size()==1;
    }
    
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    public boolean remove(int val) {
        if(map.containsKey(val)){
            int lastIndex = n-1;//得到最後2個值索引
            Set lastset = map.get(list.get(lastIndex));
            Set set = map.get(val);
            int currIndex = (int)set.iterator().next();//得到當前值索引
            //進行刪除操作
            swap(list, currIndex, lastIndex);
            list.remove(n-1);//將其在列表中刪除
            set.remove(currIndex);//刪除原值
            if(set.size()==0)   map.remove(val);//在圖中刪除
            //修改最後一個值的索引
            lastset.remove(n-1);
            lastset.add(currIndex);
            n--;
        }else{
            return false;
        }
        return true;
    }
    
    /** Get a random element from the collection. */
    public int getRandom() {
        return list.get(random.nextInt(n));
    }
    private void swap(List<Integer> list ,int i,int j){
        int temp = list.get(i);
        list.set(i, list.get(j));
        list.set(j, temp);
    }
}

/**
 * Your RandomizedCollection object will be instantiated and called as such:
 * RandomizedCollection obj = new RandomizedCollection();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */