LeetCode 381: O(1) 时间插入、删除和获取随机元素 - 允许重复

Leetcode380不同的是,这道题允许元素重复

代码逻辑

1. 插入操作
java 复制代码
public boolean insert(int val) {
    arr.add(val);  // 直接添加到数组末尾
    HashSet<Integer> set = map.getOrDefault(val, new HashSet<Integer>());
    set.add(arr.size() - 1);  // 记录该元素在数组中的索引
    map.put(val, set);
    return set.size() == 1;  // 如果是第一次插入,返回 true
}

将元素添加到数组末尾,同时在 HashMap 中记录其索引位置。

2. 删除操作
java 复制代码
public boolean remove(int val) {
    if (!map.containsKey(val)) {
        return false;
    }
    
    // 获取要删除元素的任意一个索引
    HashSet<Integer> valSet = map.get(val);
    int valAnyIndex = valSet.iterator().next();
    
    // 获取数组末尾元素
    int endValue = arr.get(arr.size() - 1);
    
    if (val == endValue) {
        // 特殊情况:要删除的就是末尾元素
        valSet.remove(arr.size() - 1);
    } else {
        // 将末尾元素移动到要删除的位置
        HashSet<Integer> endValueSet = map.get(endValue);
        endValueSet.add(valAnyIndex);  // 末尾元素有了新位置
        arr.set(valAnyIndex, endValue);  // 更新数组
        endValueSet.remove(arr.size() - 1);  // 移除末尾位置
        valSet.remove(valAnyIndex);  // 移除被删除元素的位置
    }
    
    arr.remove(arr.size() - 1);  // 删除数组末尾
    
    if (valSet.isEmpty()) {
        map.remove(val);  // 如果该值已经没有了,从 map 中删除
    }
    
    return true;
}

ArrayList 删除中间元素是 O(n) 操作,但删除末尾元素是 O(1),因此我们把要删除的元素和末尾元素交换,然后删除末尾。

3. 随机获取
java 复制代码
public int getRandom() {
    return arr.get((int) (Math.random() * arr.size()));
}

完整代码

java 复制代码
class RandomizedCollection{
		public HashMap<Integer,HashSet<Integer>> map;
		public ArrayList<Integer> arr;
		public RandomizedCollection(){
			map = new HashMap<>();
			arr = new ArrayList<>();
		}

		public boolean insert(int val) {
			arr.add(val);  // 直接添加到数组末尾
			HashSet<Integer> set = map.getOrDefault(val, new HashSet<Integer>());
			set.add(arr.size() - 1);  // 记录该元素在数组中的索引
			map.put(val, set);
			return set.size() == 1;  // 如果是第一次插入,返回 true
		}

		public boolean remove(int val) {
			if (!map.containsKey(val)) {
				return false;
			}

			// 获取要删除元素的任意一个索引
			HashSet<Integer> valSet = map.get(val);
			int valAnyIndex = valSet.iterator().next();

			// 获取数组末尾元素
			int endValue = arr.get(arr.size() - 1);

			if (val == endValue) {
				// 特殊情况:要删除的就是末尾元素
				valSet.remove(arr.size() - 1);
			} else {
				// 将末尾元素移动到要删除的位置
				HashSet<Integer> endValueSet = map.get(endValue);
				endValueSet.add(valAnyIndex);  // 末尾元素有了新位置
				arr.set(valAnyIndex, endValue);  // 更新数组
				endValueSet.remove(arr.size() - 1);  // 移除末尾位置
				valSet.remove(valAnyIndex);  // 移除被删除元素的位置
			}

			arr.remove(arr.size() - 1);  // 删除数组末尾

			if (valSet.isEmpty()) {
				map.remove(val);  // 如果该值已经没有了,从 map 中删除
			}

			return true;
		}

		public int getRandom(){
			return arr.get((int) (Math.random()*arr.size()));
		}
	}
相关推荐
x***381626 分钟前
springboot和springframework版本依赖关系
java·spring boot·后端
S***848841 分钟前
SpringSecurity踢出指定用户
java
p***s9143 分钟前
Spring数据库原理 之 DataSource
java·数据库·spring
adobehu43 分钟前
麒麟系统安装jdk17
java·jdk
potato_may43 分钟前
链式二叉树 —— 用指针构建的树形世界
c语言·数据结构·算法·链表·二叉树
spencer_tseng44 分钟前
java.util.IllegalFormatPrecisionException
java·printf
虹科网络安全1 小时前
艾体宝干货 | Redis Java 开发系列#1 从零开始的环境搭建与实践指南
java·数据库·redis
铅笔侠_小龙虾1 小时前
Arthas 命令
java·jvm
java修仙传1 小时前
每日一题,力扣560. 和为 K 的子数组
算法·leetcode
seeyoutlb1 小时前
微服务全局日志处理
java·python·微服务