LeetCode398-随机数索引
原题链接:【398. 随机数索引】:https://leetcode-cn.com/problems/random-pick-index/
题目描述:
给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。
注意:
数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。
示例:
int[] nums = new int[] {1,2,3,3,3};
Solution solution = new Solution(nums);
// pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
solution.pick(3);
// pick(1) 应该返回 0。因为只有nums[0]等于1。
solution.pick(1);
解题思路:
解法1:哈希表。
暴力解法。使用哈希表存储数组中每个元素值到其所有的下标索引的映射。
即key为元素值,value为元素值对应的索引下标列表。
再用random函数,从下标列表中随机选择一个索引返回即可。
这个解法非常占用额外空间O(N),如果数组很大,很容易oom。
解法2:动态数组存储索引列表。
定义一个存储索引下标的索引列表indexList,用动态数组,方便扩展。
遍历数组,如果元素跟target目标值相等,则把索引值添加进indexList列表。
取随机数,rand范围为【0,indexList.length ),然后将对应位置的索引值返回即可。
概率为:1 / indexList.length
这里相比上一种解法,已经降了一个数量级,但是如果N很大,或者数字分布不均匀,indexList也可能非常大,也非常占用额外空间,空间消耗也可能会达到O(N),可能会oom。
解法3:蓄水池抽样算法。
算法是:要从超大数组N中取k个元素,这里是取一个元素,即K=1
那么每次只取一个样本值,那么逐个遍历数组,当遇到第i个数时,就以 1 / i 的概率抽取它做样本值,以(i - 1)/ i 的概率保留原来的样本值,不替换。
我们不需要保存索引下标列表,只需要一个变量cnt计数,统计匹配到了多少个相同的数字,方便后去取随机数,算概率。
遍历数组,如果元素跟target目标值相等,则cnt++,计数器+1。
然后取随机数,rand范围为【1,cnt】。
因为这里只取一个数,就是K=1的案例。
所以如果rand == 1,则取当前元素的下标,替换为结果值。
如果rand > 1,则保留之前的结果,继续往下走。知道结束返回结果值。
特点:这里只需要遍历一遍数组,而且没有额外的空间消耗,只有一个计数器变量cnt。空间复杂度为O(1)。(非常推荐)
题解代码:
代码如下:(java版)
//给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。
//
// 注意:
//数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。
//
// 示例:
//
//
//int[] nums = new int[] {1,2,3,3,3};
//Solution solution = new Solution(nums);
//
//// pick(3) 应该返回索引 2,3 或者 4。每个索引的返回概率应该相等。
//solution.pick(3);
//
//// pick(1) 应该返回 0。因为只有nums[0]等于1。
//solution.pick(1);
//
// Related Topics 水塘抽样 哈希表 数学 随机化
// 125 0 import java.util.Random; //leetcode submit region begin(Prohibit modification and deletion)
class Solution { // 需要把nums传递给pick方法,所以我们需要定义一个类变量
int[] nums;
public Solution(int[] nums) {
this.nums = nums;
} public int pick(int target) {
// 定义一个变量,存储结果值
int result = 0;
// 定义一个变量cnt,计数器,标记匹配到了几个相同的数字,方便后面取随机数范围
int cnt = 0;
// 循环遍历链表
for (int i=0; i<nums.length; i++) {
// 匹配跟target元素是否相等
if (nums[i] == target) {
// 匹配到了,则计数器+1
cnt++;
// 取随机数rand范围为[1, cnt],注意这里边界是cnt
int rand = new Random().nextInt(cnt) + 1;
// 取每个数的概率都是 1 / cnt,也就是说有1 / cnt的概率,更新结果下标值
if (rand == 1) {
// rand等于1,则取当前元素的下标,更新结果值
result = i;
}
} } // 返回结果下标
return result;
}
} /**
* Your Solution object will be instantiated and called as such:
* Solution obj = new Solution(nums);
* int param_1 = obj.pick(target);
*/
//leetcode submit region end(Prohibit modification and deletion)
LeetCode398-随机数索引的更多相关文章
- [Swift]LeetCode398. 随机数索引 | Random Pick Index
Given an array of integers with possible duplicates, randomly output the index of a given target num ...
- Java实现 LeetCode 398 随机数索引
398. 随机数索引 给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引. 您可以假设给定的数字一定存在于数组中. 注意: 数组大小可能非常大. 使用太多额外空间的解决方案将不会通过测试 ...
- 398 Random Pick Index 随机数索引
给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引. 您可以假设给定的数字一定存在于数组中.注意:数组大小可能非常大. 使用太多额外空间的解决方案将不会通过测试.示例:int[] num ...
- 产生n不同随机数的算法
昨天无聊,就模仿仙剑5外传中的卡牌游戏做了一个小游戏,结果在开发这个小游戏的时候,碰到了产生多个不同随机数的问题.我们知道,仙剑中的卡牌游戏是随机产生16张图片,并且这16张图片是两个一组的,因为只有 ...
- 求指定范围里的不重复的N个随机数
原本是朋友问了一个题目,怎样把1到25个整形数随机排列,想了想,换个意思就是说如何把25个数随机不重复显示出来,即求1—25中25个随机数的一个数组.最简单的方法即利用双循环,是在每次得到一个随机数后 ...
- leetcode398 and leetcode 382 蓄水池抽样算法
382. 链表随机节点 给定一个单链表,随机选择链表的一个节点,并返回相应的节点值.保证每个节点被选的概率一样. 进阶:如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现? 示 ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- 6月6 Smarty练习----设置题目及打印试卷
所需要的数据库表格:shiti, shititimu, timu, kemu, xuanxiang 考试试题的设置: 考试试题后台:ksset.php <?php include(" ...
- Java基础六(自定义类、ArrayList集合)
今日内容介绍1.自定义类型的定义及使用2.自定义类的内存图3.ArrayList集合的基本功能4.随机点名器案例及库存案例代码优化 ###01引用数据类型_类 * A: 数据类型 * a: java中 ...
随机推荐
- JavaScript复习 1
概括及使用方法: JavaScript编写规范 一般放在<head>-</head>中间 逐行被执行,越短越好 大小写敏感 语句是基本单位 通常以分号表示语句结束 多行语句可以 ...
- git rebase 合并提交
git rebase 合并提交 合并最近多次提交记录 语法 git rebase -i HEAD~n 1.进入合并模式 合并最近三次提交 git rebase -i HEAD~3 然后你会看到一个像下 ...
- PTA 最小堆插入元素和删除堆顶(无哨兵元素) (20分)
PTA 最小堆插入元素和删除堆顶(无哨兵元素) (20分) 对于给定的最小堆(优先队列),分别实现插入元素和删除堆顶的函数. 函数接口定义: int insertIntoHeap(struct Hea ...
- mybatis替换成mybatisplus后报错mybatisplus Invalid bound statement (not found):
项目原来是mybatis,之后由于生成代码不方便,觉得替换成mybatisplus,引入mybatisplus后,启动项目报错mybatisplus Invalid bound statement ( ...
- 第一课 Dubbo背景及原理
1 . 技术背景 Dubbo每天为2,000+个服务提供3,000,000,000+次访问量支持,并被广泛应用于阿里巴巴集团的各成员站点. Dubbo是一个阿里巴巴开源出来的一个分布式服务框架,致力于 ...
- Spring的轻量级实现
作者: Grey 原文地址:Spring的轻量级实现 本文是参考公众号:码农翻身 的从零开始造Spring 教程的学习笔记 源码 github 开发方法 使用TDD的开发方法,TDD的开发流程是: 写 ...
- 一个开源的C#和cefsharp项目:逐浪字体大师pc版上线(附源码开源)
z01逐浪字体大师,是一款基于C#和web引擎开发的字体设计软件,可以打开直接写字,也可以链接官方资源 ,附Github开源库,欢迎大家下载.客户端技术是基于wpf设计的,整个界面精美,与逐浪CMS技 ...
- Pycharm下载安装详细教程
目录 1.Pycharm 简介 2.Pycharm下载 3.环境变量的配置 4.Pycharm的使用 1.Pycharm 简介 PyCharm是一种Python IDE(Integrated Deve ...
- 力扣 - 剑指 Offer 22. 链表中倒数第k个节点
题目 剑指 Offer 22. 链表中倒数第k个节点 思路1(栈) 既然要倒数第k个节点,那我们直接把所有节点放到栈(先进后出)里面,然后pop弹出k个元素就可以了 代码 class Solution ...
- [Comet1173]最简单的题
称区间$[l,r]$的"信息"为其的答案和第一个.最后一个大于$x$的位置,显然通过$[l,mid]$和$[mid+1,r]$的信息可以$o(1)$合并得到$[l,r]$的信息 考 ...