381.Insert Delete GetRandom O(1) - Duplicates allowed(week2)

题目描述

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

解题思路

这道题复杂的地方在于,用O(1)的复杂度实现插入和删除。

如果单纯用链表实现,删除的定位操作是O(n)的复杂度;而单纯用数组或者vector的进行操作,插入操作的复杂度也是O(n)。因此,在这里,就得用到哈希表。哈希表的插入和删除操作都是O(1)的复杂度。

然而,即使用了哈希表,也不能完美的解决这道题。由于哈希表无法进行随机访问,因此无法实现getRandom函数。而能够实现线性可能性随机访问的结构只有之前提到的vector或者数组。

因此,这道题中,我们需要结合哈希表vector。

由于题目要求可能存取相同的数字,因此哈希表采用拉链的方式扩展。

插入一个新的数字到vector中时,哈希表对应键值记录下它的下标,如果有多个下标则用拉链的方法依次存储。

而在删除时,在链表中移去对应数字的下标;在vector中,先与最后一个元素交换(如果自己是最后一个元素则不需要交换),再移掉vector的最后一个元素。这里要注意,当与最后一个元素交换时,这个元素在链表中的下标也要相应的做出改变。

时间复杂度分析

在插入操作中,插入到vector中的复杂度是O(1);哈希表定位到对应链表的复杂度是O(1),将下标插入到链表的操作,由于重复元素不多,因此复杂度也是O(1)。

在删除操作中,移除链表元素的复杂度和插入一致,为O(1);交换和移除vector最后一个元素的复杂度也为O(1)。

因此,算法中任意一个操作的复杂度都是O(1)。

源码

class RandomizedCollection {

public:

/** Initialize your data structure here. */

RandomizedCollection() { }

/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */

bool insert(int val) {

// cout << "insert " << val << "\n----------\n";

bool isExist = nums_pos.find(val) != nums_pos.end();

int newIndex = nums.size();

nums_pos[val].push_back(newIndex);

nums.push_back(val);

//display(nums_pos);

//display(nums);

return !isExist;

}

/** Removes a value from the collection. Returns true if the collection contained the specified element. */

bool remove(int val) {

bool isExist = nums_pos.find(val) != nums_pos.end();

// cout << "remove " << val << "\n----------\n";

if (isExist) {

int index = nums_pos[val].back();

nums_pos[val].pop_back();

if (nums_pos[val].empty()) {

nums_pos.erase(val);

}

if (index != nums.size() -1) {

nums_pos[nums.back()].remove(nums.size() - 1);

int temp = nums.back();

nums.back() = nums[index];

nums[index] = temp;

nums_pos[temp].push_back(index);

}

nums.pop_back();

//display(nums_pos);

//display(nums);

return isExist;

} else {

return isExist;

}

}

/** Get a random element from the collection. */

int getRandom() {

return nums[rand() % nums.size()];

}

private:

vector nums;

unordered_map> nums_pos;

};

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,941评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,397评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,345评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,851评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,868评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,688评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,414评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,319评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,775评论 1 315
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,945评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,096评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,789评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,437评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,993评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,107评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,308评论 3 372
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,037评论 2 355

推荐阅读更多精彩内容