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]);
}
}
}