晨哥Leetcode 497. Random Point in Non-overlapping Rectangles

Given a list of non-overlapping axis-aligned rectangles rects, write a function pick which randomly and uniformily picks an integer point in the space covered by the rectangles.
Note:
An integer point is a point that has integer coordinates.
A point on the perimeter of a rectangle is included in the space covered by the rectangles.
ith rectangle = rects[i] = [x1,y1,x2,y2], where [x1, y1] are the integer coordinates of the bottom-left corner, and [x2, y2] are the integer coordinates of the top-right corner.
length and width of each rectangle does not exceed 2000.
1 <= rects.length <= 100
pick return a point as an array of integer coordinates [p_x, p_y]
pick is called at most 10000 times.

这题是在之前这道题的基础上做的,还没做过的同学建议先做这道
Random Pick with Weight

这道题的思路是这样,我先算出这些矩形里总共有多少个点
当前矩形里有(x2 -x1 +1) * (y2-y1+1)个
然后再做prefix sum,原理跟之前那道一样,假如分别有 4, 10, 1000个点
那么prefix sum是 4, 14, 1014
规定0-3 这四个数映射到index 0, 4-13这10个数映射到index1, 14-1013这1000个数映射到index2
这样我对[0…1014) 取一个随机数,我就可以先确定我这个点会落在哪个矩形里

具体怎么求出这个点呢?
假设是个【2,2, 3, 6】的矩形,总数为10个点,宽度是x2-x2+1: (3-2+1)=2
然后我这个随机数是12,prefix sum是 4, 14, 1014
首先我得减掉前面的prefix sum 4 (如果是0…3的数,是落在之前的矩形的,不是属于现在这个矩形的)
然后大家在纸上笔画一下,可以得到
int x = (num - base) % width;
int y = (num - base) / width;
res[0] = x + selected[0];
res[1] = y + selected[1];

class Solution {
    private int[][] rects;
    private Random rand;
    private int[] count;
    public Solution(int[][] rects) {
        this.rects = rects;
        this.rand = new Random();
        this.count = new int[rects.length];
        init();
    }
    public int[] pick() {
        int num = rand.nextInt(count[count.length-1]);//结果是【0,总点数) 左闭右开区间
        int index = Arrays.binarySearch(count, num);
        if(index >= 0) {
            index++; //对于正好匹配的情况,是属于下个矩形的
        } else {
            index = -index-1;//Arrays.binarySearch如果没有匹配上,返回的是-(插入点+1)
        }
        int[] selected = rects[index]; //找到矩形
        int base = index == 0 ? 0 : count[index-1]; //之前的矩形已经包含了多少个点
        int width = selected[2] - selected[0] + 1; 
        int x = (num - base) % width;
        int y = (num - base) / width; //x, y的偏移量
        int[] res = new int[2];
        res[0] = x + selected[0];//偏移量加上左边的x, y
        res[1] = y + selected[1];
        return res;
    }
    private void init(){
        for(int i = 0; i < rects.length;i++) {
            int cur = (rects[i][2] - rects[i][0]+1) * (rects[i][3] - rects[i][1]+1);
            count[i] = i == 0? cur : (cur+ count[i-1]);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值