Random Point in Non-overlapping Rectangles (M)
题目
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.
-
i
th 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 most10000
times.
Example 1:
Input:
["Solution","pick","pick","pick"]
[[[[1,1,5,5]]],[],[],[]]
Output:
[null,[4,1],[4,1],[3,3]]
Example 2:
Input:
["Solution","pick","pick","pick","pick","pick"]
[[[[-2,-2,-1,-1],[1,0,3,0]]],[],[],[],[],[]]
Output:
[null,[-1,-2],[2,0],[-2,-1],[3,0],[-2,-2]]
Explanation of Input Syntax:
The input is two lists: the subroutines called and their arguments. Solution
‘s constructor has one argument, the array of rectangles rects
. pick
has no arguments. Arguments are always wrapped with a list, even if there aren‘t any.
题意
给定若干个互不重叠的矩形,要求每次从这些矩形覆盖的区域中均匀随机地选出一个点。
思路
我们不能单纯的给每个矩形编号,随机选一个编号再从对应的矩形中随机选一个点,因为这样不能保证每个点被选到的概率是一样的。应该以每个矩形覆盖的面积来确定它被选到的概率。具体操作为:遍历所有矩形,每次累加当前矩形包含的点数(即面积),并以此作为当前矩形的编号,可以得到一个类似数轴的图:
记总点数为area,从区间[1, area]中随机选一个点p,那么对应的矩形编号就是p所在的颜色方块的右端点。再在这个矩形中随机选出一个点。以这种方式选取矩形能够保证每个点被选到的概率是一样的。
代码实现
Java
class Solution {
private Random random;
// 为了方便使用了TreeMap,也可以用HashMap结合二分搜索找key
private TreeMap<Integer, int[]> map;
private int area;
public Solution(int[][] rects) {
random = new Random();
map = new TreeMap<>();
for (int[] rect : rects) {
area += (rect[2] - rect[0] + 1) * (rect[3] - rect[1] + 1);
map.put(area, rect);
}
}
public int[] pick() {
int[] rect = map.get(map.ceilingKey(random.nextInt(area) + 1));
int x = rect[0] + random.nextInt(rect[2] - rect[0] + 1);
int y = rect[1] + random.nextInt(rect[3] - rect[1] + 1);
return new int[] { x, y };
}
}
/**
* Your Solution object will be instantiated and called as such: Solution obj =
* new Solution(rects); int[] param_1 = obj.pick();
*/