【LeetCode算法学习笔记】查找、删除数组中任意元素

labuladong公众号算法学习笔记

查找、删除数组中任意元素

实现随机集合

对于getRandom方法,如果想要[等概率]和[在O(1)的时间]取出元素就一定要满足:底层用数组实现,且数组必须是紧凑的。
对数组尾部进行插入和删除操作不会涉及数据搬移,时间复杂度为O(1),可以先把元素val交换到数组的尾部,然后pop出去。
交换两个元素需要索引来进行,则需要哈希表ValToIndex来记录每个元素值对应的索引。

class RandomizedSet{
	public:
		//存储元素的值 
		vector<int> nums;
		//记录每个元素对应在nums中的索引
		unordered_map<int,int> valToIndex;
		
		bool insert(int val){
			//如果val已经存在,则不需要插入
			if(valToIndex.count(val)) return false;
			//如果val不存在,则插入到数组尾部,并记录val对应的索引
			valToIndex[val] = nums.size();
			nums.push_back(val);
			return true; 
		}
		
		bool remove(int val){
			//若val不存在,不用删除
			if(!valToIndex.count(val)) return false;
			//先拿到val的索引 
			int index = valToIndex[val];
			//将最后一个元素对应的索引修改为index
			valToIndex[nums.back()] = index;
			//交换最后一个元素和val
			swap(nums[index],nums.back());
			//在数组中删除元素val
			nums.pop_back();
			//删除元素val对应的索引
			valToIndex.erase(val);
			return true; 
		}
		
		int getRandom(){
			return nums[rand() % nums.size()];
		}
};

避开黑名单的随机数

可以将区间[0,N)看做一个数组,然后将blacklist中的元素移到数组最末尾,同时用一个哈希表进行映射。
对mapping[b]赋值时,要保证last一定不在blacklist中。

class Solution{
	public:
		int sz;
		unordered_map<int,int> mapping;
		
		Solution(int N,vector<int>& blacklist){
			sz=N-nums.size();
			for(int b:black){
				//赋值多少都可以,目的在于把键存在哈希表中,
				//方便快速判断数字是否在黑名单内
				mapping[b]=666;
			}
			int last=N-1;
			for(int b:blacklist){
				if(b>=sz){
					continue;
				}
				while(mapping.count(last)){
					last--;
				}
				mapping[b]=last;
				last--;
			}
		}
		
		int pick(){
			int index=rand()%sz;
			//这个索引中了黑名单,需要被映射到其他位置 
			if(mapping.count(index)){
				return mapping[index];
			}
			//如果没有中黑名单,直接返回 
			return index;
		}
};

总结

1、想要高效地,等概率地随机获取元素,就要使用数组作为底层容器。
2、要保持数组的紧凑性,可以把待删除元素换到最后,然后pop掉末尾的元素,这样复杂度为O(1),需要额外的哈希表记录值到索引的映射。
3、数组中含有黑名单,可以利用哈希表巧妙处理映射关系,让数组在逻辑上紧凑,方便获取元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值