[LeetCode 381] Insert Delete GetRandom O(1) - Duplicates allowed (Hard)

Design a data structure that supports all following operations in average O(1) time.

Note: Duplicate elements are allowed.

  • insert(val): Inserts an item val to the collection.
  • remove(val): Removes an item val from the collection if present.
  • getRandom: Returns a random element from current collection of elements. The probability of each element being returned is linearly related to the number of same value the collection contains.

Example:

// Init an empty collection.
RandomizedCollection collection = new RandomizedCollection();

// Inserts 1 to the collection. Returns true as the collection did not contain 1.
collection.insert(1);

// Inserts another 1 to the collection. Returns false as the collection contained 1. Collection now contains [1,1].
collection.insert(1);

// Inserts 2 to the collection, returns true. Collection now contains [1,1,2].
collection.insert(2);

// getRandom should return 1 with the probability 2/3, and returns 2 with the probability 1/3.
collection.getRandom();

// Removes 1 from the collection, returns true. Collection now contains [1,2].
collection.remove(1);

// getRandom should return 1 and 2 both equally likely.
collection.getRandom();

Solution:

參考http://zxi.mytechroad.com/blog/hashtable/leetcode-381-insert-delete-getrandom-o1-duplicates-allowed/

  1. 思路與#380類似蕉汪,但不同在于有重復(fù)的數(shù)字笛洛。所以需要用HashMap<Integer, List<Integer>>List<Node>兩個數(shù)據(jù)結(jié)構(gòu)。

    • HashMap: 用于存儲每個數(shù)字,和其在List中的Index
    • Node:An object, val ~ number, indexInMap ~ 當(dāng)前數(shù)字在Map的List<Integer>中對應(yīng)的Index
    • List<Node>: 數(shù)字node的list
      image.png
  2. Insert:需要向List<Node>中加入node,同時更新Map

  3. remove: 難點!琳要! 同樣也是與尾部的number交換,然后移除到尾部的數(shù)字秤茅。難點在于update index in map for last element

  4. getRandom: 與#380相同稚补。

//3. update index in map for the last element
        numberVsIndexes.get(lastEntry.val).set (lastEntry.indexInMap, removeIndex);
class RandomizedCollection {
    class Node {
        public int val;
        public int indexInMap;
        
        public Node (int val, int index) {
            this.val = val;
            this.indexInMap = index;
        }
    }
    
    Map<Integer, List<Integer>> numberVsIndexes;
    List<Node> nodeList;

    /** Initialize your data structure here. */
    public RandomizedCollection() {
        numberVsIndexes = new HashMap<Integer, List<Integer>> ();
        nodeList = new ArrayList<Node> ();
    }
    
    /** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
    public boolean insert(int val) {
        boolean result = false;
        if (!numberVsIndexes.containsKey (val)) {
            result = true;
        }
        
        int indexInNodeList = nodeList.size ();
        List<Integer> indexes = numberVsIndexes.getOrDefault (val, new ArrayList<Integer> ());
        indexes.add (indexInNodeList);
        numberVsIndexes.put (val, indexes);
        
        int indexInMap = indexes.size () - 1;
        Node node = new Node (val, indexInMap);
        nodeList.add (node);
        
        return result;
    }
    
    /** Removes a value from the collection. Returns true if the collection contained the specified element. */
    public boolean remove(int val) {
        if (!numberVsIndexes.containsKey (val)) {
            return false;
        }
        
        //1. get the last entry of the remove number
        List<Integer> removeCandidates = numberVsIndexes.get (val);
        int removeIndex = removeCandidates.get (removeCandidates.size () - 1);
        
        //2. get the last entry of the nodeList
        Node lastEntry = nodeList.get (nodeList.size () - 1);
        
        //3. update index in map for the last element
        numberVsIndexes.get(lastEntry.val).set (lastEntry.indexInMap, removeIndex);
        
        //3. swap 
        nodeList.set (removeIndex, lastEntry);
        
        //4. clean up the map
        nodeList.remove (nodeList.size () - 1);
        removeCandidates.remove (removeCandidates.size () - 1);
        
        if (removeCandidates.size () == 0) {
            numberVsIndexes.remove (val);
        }
        
        return true;
    }
    
    /** Get a random element from the collection. */
    public int getRandom() {
        Random rand = new Random ();
        return nodeList.get (rand.nextInt (nodeList.size ())).val;
    }
}

/**
 * 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();
 */
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市框喳,隨后出現(xiàn)的幾起案子课幕,更是在濱河造成了極大的恐慌厦坛,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乍惊,死亡現(xiàn)場離奇詭異杜秸,居然都是意外死亡,警方通過查閱死者的電腦和手機润绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門撬碟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人莉撇,你說我怎么就攤上這事呢蛤。” “怎么了棍郎?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵顾稀,是天一觀的道長。 經(jīng)常有香客問我坝撑,道長,這世上最難降的妖魔是什么粮揉? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任巡李,我火速辦了婚禮,結(jié)果婚禮上扶认,老公的妹妹穿的比我還像新娘侨拦。我一直安慰自己,他們只是感情好辐宾,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布狱从。 她就那樣靜靜地躺著,像睡著了一般叠纹。 火紅的嫁衣襯著肌膚如雪季研。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天誉察,我揣著相機與錄音与涡,去河邊找鬼。 笑死持偏,一個胖子當(dāng)著我的面吹牛驼卖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鸿秆,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼酌畜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卿叽?” 一聲冷哼從身側(cè)響起桥胞,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤恳守,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后埠戳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體井誉,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年整胃,在試婚紗的時候發(fā)現(xiàn)自己被綠了颗圣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡屁使,死狀恐怖在岂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蛮寂,我是刑警寧澤蔽午,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站酬蹋,受9級特大地震影響及老,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜范抓,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一骄恶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匕垫,春花似錦僧鲁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至偶惠,卻和暖如春春寿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背忽孽。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工堂淡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扒腕。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓绢淀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瘾腰。 傳聞我的和親對象是個殘疾皇子皆的,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容