每日算法-力扣380
解法#
python解法#
import random
class RandomizedSet:
def __init__(self):
self.nums = []
self.val2idx = dict() # val: index
def insert(self, val):
if val in self.val2idx:
return False
self.val2idx[val] = len(self.nums)
self.nums.append(val)
return True
def remove(self, val):
if val not in self.val2idx:
return False
# O(1)取下标,不再index遍历
idx = self.val2idx[val]
last = self.nums[-1]
# 末尾元素覆盖+更新map
self.nums[idx] = last
self.val2idx[last] = idx
# 删尾部、删key
self.nums.pop()
del self.val2idx[val]
return True
def getRandom(self):
return random.choice(self.nums)
Java解法#
public class RandomizedSet {
private ArrayList<Integer> nums;
private HashMap<Integer, Integer> valIndexMap;
private Random random;
public RandomizedSet() {
nums = new ArrayList<>();
valIndexMap = new HashMap<>();
random = new Random();
}
// O(1)插入
public boolean insert(int val) {
if (valIndexMap.containsKey(val)) {
return false;
}
// 新元素放在数组末尾
valIndexMap.put(val, nums.size());
nums.add(val);
return true;
}
// O(1)删除:目标位置和末尾交换,删除尾部
public boolean remove(int val) {
if (!valIndexMap.containsKey(val)) {
return false;
}
// 1.O(1)获取待删下标、最后一个元素
int delIndex = valIndexMap.get(val);
int lastVal = nums.get(nums.size() - 1);
// 2.末尾元素覆盖待删位置
nums.set(delIndex, lastVal);
// 3.更新末尾元素的下标映射
valIndexMap.put(lastVal, delIndex);
// 4.删除末尾元素 + 删除map中val
nums.remove(nums.size() - 1);
valIndexMap.remove(val);
return true;
}
// O(1)随机等概率取元素
public int getRandom() {
int randIdx = random.nextInt(nums.size());
return nums.get(randIdx);
}
}
Go解法#
package main
import (
"math/rand"
"time"
)
type RandomizedSet struct {
nums []int
idxMap map[int]int
}
func Constructor() RandomizedSet {
rand.Seed(time.Now().UnixNano())
return RandomizedSet{
nums: make([]int, 0),
idxMap: make(map[int]int),
}
}
// 插入
func (rs *RandomizedSet) Insert(val int) bool {
if _, ok := rs.idxMap[val]; ok {
return false
}
rs.idxMap[val] = len(rs.nums)
rs.nums = append(rs.nums, val)
return true
}
// 删除
func (rs *RandomizedSet) Remove(val int) bool {
index, ok := rs.idxMap[val]
if !ok {
return false
}
lastVal := rs.nums[len(rs.nums)-1]
// 末尾值覆盖要删除的下标
rs.nums[index] = lastVal
// 更新末尾元素的下标映射
rs.idxMap[lastVal] = index
// 截断最后一位 O(1)
rs.nums = rs.nums[:len(rs.nums)-1]
// map删掉目标key
delete(rs.idxMap, val)
return true
}
// 随机等概率取一个
func (rs *RandomizedSet) GetRandom() int {
return rs.nums[rand.Intn(len(rs.nums))]
}
总结#
三种方法虽然属于不同编程语言,但是原理都是一样的,提供k-v型的数据结构保存下标和值的关系,再用数组存储唯一值 之所以不选择set来存储唯一值,是因为set不方便实现等概率读取。本算法的关键在于,将被删元素与数组末尾元素互换,完成了O(1)的删除操作。 k-v结构,又实现了O(1)的查找工作。
原创
algorithm-001
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法