「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战」
题目
给你一个 m x n 的二元矩阵 matrix ,且所有值被初始化为 0 。请你设计一个算法,随机选取一个满足 matrix[i][j] == 0 的下标 (i, j) ,并将它的值变为 1 。所有满足 matrix[i][j] == 0 的下标 (i, j) 被选取的概率应当均等。
尽量最少调用内置的随机函数,并且优化时间和空间复杂度。
实现 Solution 类:
- Solution(int m, int n) 使用二元矩阵的大小 m 和 n 初始化该对象
- int[] flip() 返回一个满足 matrix[i][j] == 0 的随机下标 [i, j] ,并将其对应格子中的值变为 1
- void reset() 将矩阵中所有的值重置为 0
哈希表
首先如果使用这个复杂度的二维数组,再随机返回i,j和操作二维数组数据;思路没有问题,但是时间复杂度肯定非常高;
所以为了降低复杂度可以将二维数组降低为一维数组;
随机的时候,随机一维数组长度;得到一个随机值;数组长度-1;
为什么数组长度-1;
因为要保证下次随机不包含本次已经随机到的数;
哪还有一个问题,如果数组长度为20;第一次随机到7,数组长度-1为19;第二次在随机得到7呢?
解答:第一次随机到7,将20放在map中,map中数据结构key为7,value为20;第二次在随机到7,将20丢出去;
为什么把20丢出去?因为在第二次随机的最大值是19,不可能是20,以后都不可能,但是可以是7,实际上是将7代替了已经随机不到的20;7可以随机得到,但是永远不能再次出现
将20丢出去,再将19放进来。
因为第3次随机的时候最大值已经是18了,这是的7就代表了19;
你理解了吗?
动态图
图片
动态图动的太快了,不太容易看到;后续会改进; 可以看下面的的图了解具体思路
图中注释非常重要
代码#
根据上述图片思路编辑代码如下
/**
* @param {number} m
* @param {number} n
*/
var Solution = function (m, n) {
this.m = m
this.n = n
this.total = m * n
this.map = new Map()
}
/**
* @return {number[]}
*/
Solution.prototype.flip = function (index) {
const key = [8, 8, 4, 7, 7][index]
this.total--
const idx = this.map.get(key) || key
this.map.set(key, this.map.get(this.total) || this.total)
console.log('map', key, this.map)
return [Math.floor(idx / this.n), idx % this.n]
}
/**
* @return {void}
*/
Solution.prototype.reset = function () {
this.total = this.m * this.n
this.map.clear()
}