【宫水三叶的刷题日记】497. 非重叠矩形中的随机点(中等)

题目描述

这是 LeetCode 上的 497. 非重叠矩形中的随机点 ,难度为 中等

Tag : 「前缀和」、「二分」、「随机化」

给定一个由非重叠的轴对齐矩形的数组 rects,其中 表示 是第 个矩形的左下角点, 是第 个矩形的右上角点。

设计一个算法来随机挑选一个被某一矩形覆盖的整数点。矩形周长上的点也算做是被矩形覆盖。所有满足要求的点必须等概率被返回。

在给定的矩形覆盖的空间内的任何整数点都有可能被返回。

请注意 ,整数点是具有整数坐标的点。

实现 Solution 类:

  • Solution(int[][] rects) 用给定的矩形数组  rects 初始化对象。
  • int[] pick() 返回一个随机的整数点 在给定的矩形所覆盖的空间内。

示例 1: alt

输入: 
["Solution""pick""pick""pick""pick""pick"]
[[[[-2, -2, 1, 1], [2, 2, 4, 6]]], [], [], [], [], []]

输出: 
[null, [1, -2], [1, -1], [-1, -2], [-2, -2], [0, 0]]

解释:
Solution solution = new Solution([[-2, -2, 1, 1], [2, 2, 4, 6]]);
solution.pick(); // 返回 [1, -2]
solution.pick(); // 返回 [1, -1]
solution.pick(); // 返回 [-1, -2]
solution.pick(); // 返回 [-2, -2]
solution.pick(); // 返回 [0, 0]

提示:

  • 所有的矩形不重叠。
  • pick 最多被调用   次。

前缀和 + 二分

为了方便,我们使用 rs 来代指 rects,定义某个矩阵内整数点的数量为「面积」。

一个朴素的想法是「先随机使用哪个矩形,再随机该矩形内的点」,其中后者是极其容易的,根据矩形特质,只需在该矩形的 XY 坐标范围内随机即可确保等概率,而前者(随机使用哪个矩形)为了确保是等概率,我们不能简单随机坐标,而需要结合面积来做。

具体的,我们可以预处理前缀和数组 sum(前缀和数组下标默认从 开始),其中 代表前 个矩形的面积之和(即下标范围 的面积总和),最终 为所有矩形的总面积,我们可以在 范围内随机,假定随机到的值为 ,然后利用 sum 数组的具有单调性,进行「二分」,找到 所在的矩形(每个矩形均会贡献面积,可看做是每个矩形在数轴 内贡献一段长度为面积的连续段,我们二分是为了找到点 所在的连续段是由哪个矩形所贡献),然后在该矩形中进行随机,得到最终的随机点。

代码:

class Solution {
    int[][] rs;
    int[] sum;
    int n;
    Random random = new Random();
    public Solution(int[][] rects) {
        rs = rects;
        n = rs.length;
        sum = new int[n + 1];
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (rs[i - 1][2] - rs[i - 1][0] + 1) * (rs[i - 1][3] - rs[i - 1][1] + 1);
    }
    public int[] pick() {
        int val = random.nextInt(sum[n]) + 1;
        int l = 0, r = n;
        while (l < r) {
            int mid = l + r >> 1;
            if (sum[mid] >= val) r = mid;
            else l = mid + 1;
        }
        int[] cur = rs[r - 1];
        int x = random.nextInt(cur[2] - cur[0] + 1) + cur[0], y = random.nextInt(cur[3] - cur[1] + 1) + cur[1];
        return new int[]{x, y};
    }
}
  • 时间复杂度:令 为给定的 rs 数组长度。初始化 Solution 时需要预处理前缀和数组,复杂度为 ;每次 pick 时需要在矩形个数 范围内进行二分,复杂度为
  • 空间复杂度:

最后

这是我们「刷穿 LeetCode」系列文章的第 No.497 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。

在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

alt

本文由 mdnice 多平台发布

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值