持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
前言
今天的题目为中等,之前碰到过的随机采样问题,随机采样问题的关键,是要考虑的范围要够广泛,部分随机并不是真的随机。
每日一题
今天的题目是 497. 非重叠矩形中的随机点,难度为中等
给定一个由非重叠的轴对齐矩形的数组 rects ,其中 rects[i] = [ai, bi, xi, yi] 表示 (ai, bi) 是第 i 个矩形的左下角点,(xi, yi) 是第 i 个矩形的右上角点。设计一个算法来随机挑选一个被某一矩形覆盖的整数点。矩形周长上的点也算做是被矩形覆盖。所有满足要求的点必须等概率被返回。
在给定的矩形覆盖的空间内的任何整数点都有可能被返回。
- 请注意 ,整数点是具有整数坐标的点。
实现 Solution 类:
- Solution(int[][] rects) 用给定的矩形数组 rects 初始化对象。
- int[] pick() 返回一个随机的整数点 [u, v] 在给定的矩形所覆盖的空间内。
示例 1:
输入:
["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]
提示:
- 1 <= rects.length <= 100
- rects[i].length == 4
- -109 <= ai < xi <= 109
- -109 <= bi < yi <= 109
- xi - ai <= 2000
- yi - bi <= 2000
- 所有的矩形不重叠。
- pick 最多被调用 104 次。
题解
随机取样
本道题的关键也是在于如何在多个不同大小的区间内随机取样,和前几天的在圆里面随机取样是否的类似。
首先想到的思路可能会是先随机一个矩形,然后去这个矩形里面随机取一个整数点,那么就会导致,不同的矩形取得的概率是一样的,但是矩形内部的整数点的个数是不一样的,比方说要是有两个矩形大小相差很大,但是他们获取的概率是一样的,那么就会照成,小的矩形内部的点取到的概率会比大的矩形内部的来的大。
所以我们可以采用每一个举行内部能够求得的点来作为它的比重来进行矩形之间的随机取样。
对于一个矩形来说,矩形 rects[i] 的左下角点为 (a, b), 右上角点为 (x, y),则它覆盖的整数点有 s = (x-a+1)*(y-b+1) 个
然后计算每一个矩形内部的点并且相加,我们就能够拿到所有的点的个数 sum,然后从 0-sum 中随机取一个点,判断这个点在哪个矩形内部,然后在这个矩形中随机取一个点,就能够拿到答案了。
class Solution {
rects: number[][]
s: number[]
sum: number
constructor(rects: number[][]) {
this.rects = rects;
const l = rects.length;
this.s = rects.map((item) => {
return (item[2] - item[0] + 1) * (item[3] - item[1] + 1);
});
for (let i = 1; i < l; i++) {
this.s[i] = this.s[i - 1] + this.s[i];
}
this.sum = this.s[l - 1];
}
pick(): number[] {
let num = Math.random() * this.sum;
const index = this.s.findIndex((item) => {
return item >= num;
});
const item = this.rects[index];
const width = item[2] - item[0];
const height = item[3] - item[1];
const widthRandom = Math.floor(Math.random() * (width + 1));
const heightRandom = Math.floor(Math.random() * (height + 1));
return [item[0] + widthRandom, item[1] + heightRandom];
};
}
/**
* Your Solution object will be instantiated and called as such:
* var obj = new Solution(rects)
* var param_1 = obj.pick()
*/