一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第20天,点击查看活动详情。
前言
今天的题目为中等,跟之前碰到过的一道题思路很相似,利用map表来空间换时间,以此来做到节省时间复杂度。
每日一题
今天的题目是 398. 随机数索引,难度为中等
-
给你一个可能含有 重复元素 的整数数组 nums ,请你随机输出给定的目标数字 target 的索引。你可以假设给定的数字一定存在于数组中。
-
实现 Solution 类:
-
Solution(int[] nums) 用数组 nums 初始化对象。
-
int pick(int target) 从 nums 中选出一个满足 nums[i] == target 的随机索引 i 。如果存在多个有效的索引,则每个索引的返回概率应当相等。
示例:
输入
["Solution", "pick", "pick", "pick"]
[[[1, 2, 3, 3, 3]], [3], [1], [3]]
输出
[null, 4, 0, 2]
解释
Solution solution = new Solution([1, 2, 3, 3, 3]);
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
solution.pick(1); // 返回 0 。因为只有 nums[0] 等于 1 。
solution.pick(3); // 随机返回索引 2, 3 或者 4 之一。每个索引的返回概率应该相等。
提示:
- 1 <= nums.length <= 2 * 104
- -231 <= nums[i] <= 231 - 1
- target 是 nums 中的一个整数
- 最多调用 pick 函数 104 次
题解
哈希表
首先题目看似非常的简单,就一个类,初始化一个数组,还有一个每次调用返回指定值随机下标的方法,看似简单的题目我们要考虑到,pick 方法的调用次数可能会非常多次,如果是在pick这个方法中去查找这个值它对应的下标的话,那无疑是非常耗时的,可以说是肯定会超时,所以这时候就需要以空间来换时间,这道题的做法和之前一道题很相似,都是会去频繁的调用一个数组查找方法,这种时候肯定需要去想,如何优化这个数组中找一个数的时间复杂度。
答案就是哈希表,我们可以实现把数组的每一个值它对应的下标存到一个哈希表当中去,这样子每次去查找的话就只是去哈希表中取值,只需要 O(1) 的时间复杂度,我们把数组循环方法提升到实例化的时候去完成,这样就可以最大程度的节省 pick 方法的时间复杂度,避免超时。
初始化类的时候新建一个哈希表,然后循环传入的数组,将每一个值存到对应的哈希表当中,当然,存起来的是一个数组,代表每一个出现的下标。
这样 pick 方法就只需要去拿到值对应的数组,然后使用随机数方法随机返回一个值就ok了。
class Solution {
constructor(arr){
this.map = new Map()
arr.forEach((e,i)=>{
this.map.set(e,this.map.has(e)?[...this.map.get(e),i]:[i])
})
}
pick(target){
let arr = this.map.get(target)
let n = arr.length
return arr[Math.floor(Math.random() * n)];
}
}
蓄水池抽样
蓄水池抽样主要是用来解决下面的问题
给定一个数据流,数据流长度N很大,且N直到处理完所有数据之前都不可知,请问如何在只遍历一遍数据(O(N))的情况下,能够随机选取出m个不重复的数据。
这道题也可以采用蓄水池抽样算法来进行解答,我们循环数组就相当于是一个数据流,然后我们要从流出来的满足我们条件的数据中,随机选取一个。
感兴趣的小伙伴可以去了解一下