题目
题目解析
首先读懂出这种问题的意图:
这是要我们随机构造得到一个符合要求的矩阵位置!注意仅仅只是得到符合要求的位置,我们不需要真正的去构建这样一个矩阵,但是我们需要通过要求模拟每次对矩阵操作的影响。
如何解题?
我们先观察每一次 flip
后的现象,由于 flip
只对没有被翻转过的位置有效(为0的位置),而每一次进行 reset
操作后,都会重置之前进行的 flip
操作。
首先我们通过一维来表示二维以方便取随机数的映射,其次我们需要进行一个 分块
的操作,这个操作主要是应对,如果随机的过程中出现不符合要求的位置(为1的位置),这说明已经被 flip
操作过。如何分块?我们想象一个连续的数组,左边一块我们分来用于随机(直接 %size
得到随机结果),如果出现碰撞,那么我们把 %size
的值映射到右半边去,比如映射到 size
位置,如果size位置还是碰撞,那么再继续映射到size的下一个映射位置。
可能大家会有一个问题:
如果我们第一次就随机的 totalSize-1
,那会不会导致下一次再取到这个 totalSize-1
呢?
完全不用担心,因为每次取完后 total会被-1
,那么下次无论如何都不可能被 %total
给取到了。
手写了两个具体随机过程:
解题代码
class Solution {
public:
Solution(int m, int n) {
this->m = m;
this->n = n;
this->total = m * n;
srand(time(nullptr));
}
vector<int> flip() {
int x = rand() % total;
vector<int> ans;
// 查找位置 x 对应的映射
if (map.count(x)) {
int num = map[x];
ans = {
num / n, num % n};
} else {
ans = {
x / n, x % n};
}
//x这个位置我们现在已经算是flip过了,所以把下一个碰撞后能够得到的位置给它准备好!
if (map.count(total-1)) {
map[x] = map[total-1];//如果total位置被取过,则取total位置的下一个预设位置
} else {
//如果total位置未被取过,则取该位置为下一次x产生碰撞的位置
map[x] = total-1;
}
total--;
return ans;
}
void reset() {
total = m * n;
map.clear();
}
private:
int m;
int n;
int total;
unordered_map<int, int> map;
};