「LeetCode」497-非重叠矩形中的随机点

180 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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:

image.png

输入: 
["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
  • -10^9 <= ai < xi <= 10^9
  • -10^9 <= bi < yi <= 10^9
  • xi - ai <= 2000
  • yi - bi <= 2000
  • 所有的矩形不重叠。
  • pick 最多被调用 10^4 次。

二、思路分析:

这道题的难度在于:如何取到随机的轴对称矩形,之后又是如何在该矩形中找到随机的整数点的位置?能够解答出这两个问题,那么这道题目就能够完整地解答出来,基本的步骤是:

  • 首先创建Map数据结构来存储矩形的面积,从0开始统计直至所有矩形的体积全部都叠加完成。
  • 存储完成后,选取一个0-最大面积的随机数,利用这个随机面积数去寻找它对应的矩形,这里利用到的是一个二分查找的方法。
  • 找到对应的矩形后,找出它的左下角点右上角点的位置,然后再次随机从xy的区间中找到随机点的位置即可完成作答。

三、代码:

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()
 */

四、总结:

这道题目是今日的每日一题,做起来还是挺有意思的,需要从题目中找寻关键点进行解答,本题的关键点就是上述说的两点,只要能够解决这两点就可以完成题目的作答。