[LintCode 657] Insert Delete GetRandom O(1)

Author Avatar
DataLeoZ 7月 08, 2019
  • 在其它设备中阅读本文章

Description

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

insert(val): Inserts an item val to the set if not already present.
remove(val): Removes an item val from the set if present.
getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.

设计一个数据结构实现在平均 O(1) 的复杂度下执行以下所有的操作。

insert(val): 如果这个元素不在set中,则插入。

remove(val): 如果这个元素在set中,则从set中移除。

getRandom: 随机从set中返回一个元素。每一个元素返回的可能性必须相同。

https://www.lintcode.com/problem/insert-delete-getrandom-o1/description

Example:

// 初始化空集set
RandomizedSet randomSet = new RandomizedSet();

// 1插入set中。返回正确因为1被成功插入
randomSet.insert(1);

// 返回错误因为2不在set中
randomSet.remove(2);

// 2插入set中,返回正确,set现在有[1,2]。
randomSet.insert(2);

// getRandom 应该随机的返回1或2。
randomSet.getRandom();

// 从set中移除1,返回正确。set现在有[2]。
randomSet.remove(1);

// 2已经在set中,返回错误。
randomSet.insert(2);

// 因为2是set中唯一的数字,所以getRandom总是返回2。
randomSet.getRandom();

Note

  1. O(1)下进行插入和移除操作需要直接在尾部添加元素,并在需要删除某一元素时知晓其位置信息直接进行操作,而不需要遍历
  2. HashMap可以用来保存数组中数字的下标及其数值的对应关系
  3. 对于is in 操作,在Dictionary中可以保证O(1)时间完成,而在Array不可以,会是O(n)

    下列描述来自九章算法

使用数组来保存当前集合中的元素,同时用一个hashMap来保存数字与它在数组中下标的对应关系。

插入操作时:

若已存在此元素返回false
不存在时将新的元素插入数组最后一位,同时更新hashMap。
删除操作时:

若不存在此元素返回false
存在时先根据hashMap得到要删除数字的下标,再将数组的最后一个数放到需要删除的数的位置上,删除数组最后一位,同时更新hashMap。
获取随机数操作时:

根据数组的长度来获取一个随机的下标,再根据下标获取元素。

Update Review

Code

Python3 on LintCode
check in vals is better than nums!

import random

class RandomizedSet(object):

    def __init__(self):
        # do intialization if necessary
        self.nums = []
        self.vals = {}

    """
    @param: val: a value to the set
    @return: true if the set did not already contain the specified element or false
    """
    def insert(self, val):
        # write your code here
        if val in self.nums:
            return False 
        self.nums.append(val)
        self.vals[val] = len(self.nums) - 1
        return True

    """
    @param: val: a value from the set
    @return: true if the set contained the specified element or false
    """
    def remove(self, val):
        # write your code here
        # check in vals is better than nums!
        if val not in self.vals:
            return False 
        index, last = self.vals[val], self.nums[-1]
        self.vals[index], self.vals[last] = last, index
        self.nums.pop()
        del self.vals[val]
        return True

    """
    @return: Get a random element from the set
    """
    def getRandom(self):
        # write your code here
        return self.nums[random.randint(0, len(self.nums) - 1)]

# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param = obj.insert(val)
# param = obj.remove(val)
# param = obj.getRandom()

Ref Code

本参考程序来自九章算法

import random

class RandomizedSet(object):

    def __init__(self):
        # do initialize if necessary    
        self.nums, self.pos = [], {}

    # @param {int} val Inserts a value to the set
    # Returns {bool} true if the set did not already contain the specified element or false
    def insert(self, val):
        if val in self.pos:
            return False

        self.nums.append(val)
        self.pos[val] = len(self.nums) - 1
        return True

    # @param {int} val Removes a value from the set
    # Return {bool} true if the set contained the specified element or false
    def remove(self, val):
        # Write your code here
        if val not in self.pos:
            return False

        idx, last = self.pos[val], self.nums[-1]
        self.nums[idx], self.pos[last] = last, idx
        self.nums.pop()
        del self.pos[val]
        return True

    # return {int} a random number from the set
    def getRandom(self):
        return self.nums[random.randint(0, len(self.nums) - 1)]


# Your RandomizedSet object will be instantiated and called as such:
# obj = RandomizedSet()
# param = obj.insert(val)
# param = obj.remove(val)
# param = obj.getRandom()

This blog is under a CC BY-NC-SA 3.0 Unported License
本文使用 CC BY-NC-SA 3.0 中国 协议许可
署名-非商业性使用-相同方式共享(BY-NC-SA):使用者可以对本创作进行共享、演绎,但使用时须进行署名(同时标明是否(对原始作品)作了修改),且不得运用于商业目的,采用本创作的内容必须同样采用本协议进行授权。详情请参考协议细则。

本文链接:https://dataleoz.com/lintcode-insert-delete-getrandom/