持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
一.题目:
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 <= 100rects[i].length == 4-10^9 <= ai < xi <= 10^9-10^9 <= bi < yi <= 10^9xi - ai <= 2000yi - bi <= 2000- 所有的矩形不重叠。
pick最多被调用10^4次。
二、思路分析:
这道题的难度在于:如何取到随机的轴对称矩形,之后又是如何在该矩形中找到随机的整数点的位置?能够解答出这两个问题,那么这道题目就能够完整地解答出来,基本的步骤是:
- 首先创建
Map数据结构来存储矩形的面积,从0开始统计直至所有矩形的体积全部都叠加完成。 - 存储完成后,选取一个
0-最大面积的随机数,利用这个随机面积数去寻找它对应的矩形,这里利用到的是一个二分查找的方法。 - 找到对应的矩形后,找出它的左下角点和右上角点的位置,然后再次随机从
x,y的区间中找到随机点的位置即可完成作答。
三、代码:
class Solution {
rects: number[][];
total: number = 0;
areaMap: Map<number,number>;
constructor(rects: number[][]) {
this.rects = rects;
const areaMap = new Map();
this.areaMap = areaMap;
let index = 0;
for(const [x1, y1, x2, y2] of this.rects){
const area = (x2 - x1 + 1) * (y2 - y1 + 1);
this.total += area;
this.areaMap.set(index++ , this.total);
}
}
pick(): number[] {
//先选取一个随机数
const randomNum = Math.floor(Math.random() * (this.total + 1));
//二分查找查找位置
const areaNum = this.bineraySearch(randomNum);
const [x1, y1, x2, y2] = this.rects[areaNum]
const x = x1 + Math.floor(Math.random() * (x2 - x1 +1));
const y = y1 + Math.floor(Math.random() * (y2 - y1 +1));
return [x,y]
}
bineraySearch(randomNum: number): number{
let left = 0, right = this.rects.length;
while(left < right){
const mid = (left + right) >>> 1;
const midArea = this.areaMap.get(mid);
if(midArea < randomNum){
left = mid + 1;
}else{
right = mid;
}
}
return left;
}
}
/**
* Your Solution object will be instantiated and called as such:
* var obj = new Solution(rects)
* var param_1 = obj.pick()
*/
四、总结:
这道题目是今日的每日一题,做起来还是挺有意思的,需要从题目中找寻关键点进行解答,本题的关键点就是上述说的两点,只要能够解决这两点就可以完成题目的作答。