​LeetCode刷题实战519:随机翻转矩阵

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 随机翻转矩阵,我们先来看题面:

https://leetcode-cn.com/problems/random-flip-matrix/

There is an m x n binary grid matrix with all the values set 0 initially. Design an algorithm to randomly pick an index (i, j) where matrix[i][j] == 0 and flips it to 1. All the indices (i, j) where matrix[i][j] == 0 should be equally likely to be returned.

Optimize your algorithm to minimize the number of calls made to the built-in random function of your language and optimize the time and space complexity.

Implement the Solution class:

Solution(int m, int n) Initializes the object with the size of the binary matrix m and n.

int[] flip() Returns a random index [i, j] of the matrix where matrix[i][j] == 0 and flips it to 1.

void reset() Resets all the values of the matrix to be 0.

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

示例                         

输入
["Solution", "flip", "flip", "flip", "reset", "flip"]
[[3, 1], [], [], [], [], []]
输出
[null, [1, 0], [2, 0], [0, 0], null, [2, 0]]

解释
Solution solution = new Solution(3, 1);
solution.flip(); // 返回 [1, 0],此时返回 [0,0]、[1,0] 和 [2,0] 的概率应当相同
solution.flip(); // 返回 [2, 0],因为 [1,0] 已经返回过了,此时返回 [2,0] 和 [0,0] 的概率应当相同
solution.flip(); // 返回 [0, 0],根据前面已经返回过的下标,此时只能返回 [0,0]
solution.reset(); // 所有值都重置为 0 ,并可以再次选择下标返回
solution.flip(); // 返回 [2, 0],此时返回 [0,0]、[1,0] 和 [2,0] 的概率应当相同

解题

1.随机产生[0, remain - 1]来保证uniform distribution,每次抽完把抽中的数跟remain交换, 因为remain不可能再被抽中了

2.但是初始化和reset一维数组需要O(nr * nc) @ 解决方法: 哈希表 O(1)

-- 初始化和reset时直接clear()

-- 只有抽到时才会生成

class Solution {
public:
    Solution(int n_rows, int n_cols) {
        nr = n_rows, nc = n_cols, remain = nr * nc;
    }

    vector<int> flip() {
        uniform_int_distribution<int> uni(0, -- remain);
        int r = uni(rng); 
        int x = S.count(r) ? S[r] : S[r] = r; // 随机数对应的值, 没的话就对应本身
        S[r] = S.count(remain) ? S[remain] : S[remain] = remain; // remain是下次需要删除的所以可以把这个值存到S[r]上,因为r已经被使用了
        return {x / nc, x % nc};
    }

    void reset() {
        S.clear();
        remain = nr * nc;
    }
private:
    unordered_map<int, int> S;
    int nr, nc, remain;
    mt19937 rng{random_device{}()};
};

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-500题汇总,希望对你有点帮助!

LeetCode刷题实战501:二叉搜索树中的众数

LeetCode刷题实战502:IPO

LeetCode刷题实战503:下一个更大元素 II

LeetCode刷题实战504:七进制数

LeetCode刷题实战505:迷宫II

LeetCode刷题实战506:相对名次

LeetCode刷题实战507:完美数

LeetCode刷题实战508:出现次数最多的子树元素和

LeetCode刷题实战509:斐波那契数

LeetCode刷题实战510:二叉搜索树中的中序后继 II

LeetCode刷题实战511:游戏玩法分析 I

LeetCode刷题实战512:游戏玩法分析 II

LeetCode刷题实战513:找树左下角的值

LeetCode刷题实战514:自由之路

LeetCode刷题实战515:在每个树行中找最大值

LeetCode刷题实战516:最长回文子序列

LeetCode刷题实战517:超级洗衣机

406f6ff12ef81ed40f05818b180c7a0f.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程IT圈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值