题目地址:
https://leetcode.com/problems/random-flip-matrix/
给定一个
m
×
n
m\times n
m×n的矩阵,一开始每个值都是
0
0
0。设计一个算法可以执行如下操作:
1、int[] flip()
:等概率随机选取一个
0
0
0将其变成
1
1
1,并且返回该位置的坐标;
2、void reset()
:重置,将每个值都变为
0
0
0。
这题等价于在长 n ′ = m × n n'=m\times n n′=m×n的一维数组 A A A上操作,不妨将这里的 n ′ n' n′也写为 n n n。开一个变量 t t t记录当前还有多少个 0 0 0,并假设我们有一个HashMap,叫 m p mp mp,它将 [ 0 , 1 , . . . , t − 1 ] [0,1,...,t-1] [0,1,...,t−1]都映射到值为 0 0 0的不同的位置,将 [ t , . . . , n − 1 ] [t,...,n-1] [t,...,n−1]都映射到值为 1 1 1的不同的位置。这样每次flip的时候,就先产生一个 [ 0 , . . . , t − 1 ] [0,...,t-1] [0,...,t−1]的随机数 x x x,然后查询 x x x映射到了哪里,不妨记为 y = m p [ x ] y=mp[x] y=mp[x],那么这个 y y y所表示的位置上的值是 0 0 0,从而可以用于返回,并且将这个位置标记为 1 1 1;接下来需要维护各个变量的含义,由于 m p [ t − 1 ] = 0 mp[t-1]=0 mp[t−1]=0,所以我们考虑执行 m p [ x ] = m p [ t − 1 ] mp[x]=mp[t-1] mp[x]=mp[t−1],这样 m p [ x ] mp[x] mp[x]所表示的位置上的数也等于 0 0 0;接下来执行 m p [ t − 1 ] = y mp[t-1]=y mp[t−1]=y,由于 y y y这个位置上的数 A [ y ] = 1 A[y]=1 A[y]=1了,即 m p [ t − 1 ] mp[t-1] mp[t−1]位置上面的数是 1 1 1,这时候执行 t − − t-- t−−,这样 t t t的含义也维护了。显然每次选取flip的位置是等概率选取的。代码如下:
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class Solution {
Map<Integer, Integer> map;
int m, n, total;
Random rand;
public Solution(int m, int n) {
// 一开始可以默认为map[x] = x,可以参考flip里的getOrDefault函数写法
map = new HashMap<>();
rand = new Random();
this.m = m;
this.n = n;
total = m * n;
}
public int[] flip() {
int x = rand.nextInt(total--);
int y = map.getOrDefault(x, x);
map.put(x, map.getOrDefault(total, total));
map.put(total, y);
// 一维映射回二维
return new int[]{y / n, y % n};
}
public void reset() {
// reset不需要重置map,因为此时map可以认为是,
// map[x]未定义则map[x] = x,也是满足条件的
total = m * n;
}
}
时间复杂度 O ( 1 ) O(1) O(1),空间 O ( m n ) O(mn) O(mn)。