Leetcode--Java--519. 随机翻转矩阵

题目描述

给你一个 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

样例描述

在这里插入图片描述

思路

二位数组一维表示 + 哈希表存储映射+ 堆删除思想
由于翻转后的位置会断开,为了保证翻转位置x后数组还是连续的,可以将最后一个值放到x的位置。
在这里插入图片描述

  1. 由于m*n最大为10的8次方,所以不能直接用一个维数组映射。用哈希表来存储映射关系。
    初始所有位置映射值为其编号本身。
  2. 首先用随机函数生成一个范围内的数x,然后获取x的映射位置idx,如果idx没有被哈希表记录过,那就直接使用idx,然后将数组末尾的数的映射指向x,保证idx的位置还能被使用(也就是让数组连续起来)。如果idx被记录过了,那就直接用idx的映射值,同时也要将数组右端左移,然后右端点的映射将其覆盖。
  3. 随机函数要放到最外面初始化,不然会报错。

代码

class Solution {
    
    
    
    int m, n, k; //k为剩余数的个数,k - 1为剩余区间右端点
    //初始映射到值本身,由于是等值映射就不需要真的记录了
    Map<Integer, Integer> map;
         //先确定随机数, 随机种子可以随便设置
        Random random = new Random();
    public Solution(int _m, int _n) {
    
    
       m = _m;
       n = _n;
       k = m * n;
  map  = new HashMap<>();;
    }
    public int[] flip() {
    
    
        //每一次翻转后,区间右端点都要左移
       int x = random.nextInt(k);
       k --;
       //有的话就用映射值,没有的话直接用初始值x
       int idx = map.getOrDefault(x, x);
       //为了保证idx的位置还能使用,数组连续,用端点的映射值覆盖到x上
       map.put(x, map.getOrDefault(k, k));
       return new int[]{
    
    idx / n, idx % n};
    }
    
    public void reset() {
    
    
      //恢复剩余数个数,并清空哈希表
      k = m * n;
      map.clear();
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(m, n);
 * int[] param_1 = obj.flip();
 * obj.reset();
 */

猜你喜欢

转载自blog.csdn.net/Sherlock_Obama/article/details/121572293