题目:
给你一个 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) -> map[i*n+j]
- 在经过m×n−k 次翻转flip 后,我们会修改map 与矩阵的映射,使得当前矩阵中有m×n−k 个 1 和 k个 0
- 利用数组中元素的交换,使得 map[0⋯k−1] 映射到矩阵中的 0,而 map[k⋯m×n−1] 映射到矩阵中的 1。该做法的好处:当进行下一次翻转操作时,我们只需要在 [0, k-1]这个区间生成随机数 x,并将 map[x] 映射到的矩阵的位置进行翻转即可
- 在将map[x] 进行翻转后,此时矩阵中有k−1 个 0,所以我们需要保证 map[0…k−2] 都映射到矩阵中的 0。由于此时map[x] 映射到了矩阵中的 1,因此我们可以将map[x] 与map[k−1] 的值进行交换,即将这个新翻转的 1 作为map[k−1] 的映射,而把原本 map[k−1] 映射到的 0 交给 x
解答:
class Solution:
def __init__(self, m: int, n: int):
self.m = m
self.n = n
self.total = m * n
self.map = {}
def flip(self) -> List[int]:
x = random.randint(0, self.total - 1)
self.total -= 1
# 查找位置 x 对应的映射,(key,default)返回指定键x的值,如果键不在字典中返回 default 设置的默认值
idx = self.map.get(x, x)
# 将位置 x 对应的映射设置为位置 total 对应的映射
self.map[x] = self.map.get(self.total, self.total)
return [idx // self.n, idx % self.n]
def reset(self) -> None:
self.total = self.m * self.n
self.map.clear()
# Your Solution object will be instantiated and called as such:
# obj = Solution(m, n)
# param_1 = obj.flip()
# obj.reset()