You are given an array of non-overlapping axis-aligned rectangles rects
where rects[i] = [ai, bi, xi, yi]
indicates that (ai, bi)
is the bottom-left corner point of the ith
rectangle and (xi, yi)
is the top-right corner point of the ith
rectangle. Design an algorithm to pick a random integer point inside the space covered by one of the given rectangles. A point on the perimeter of a rectangle is included in the space covered by the rectangle.
Any integer point inside the space covered by one of the given rectangles should be equally likely to be returned.
Note that an integer point is a point that has integer coordinates.
Implement the Solution
class:
Solution(int[][] rects)
Initializes the object with the given rectanglesrects
.int[] pick()
Returns a random integer point[u, v]
inside the space covered by one of the given rectangles.
Example 1:
Input ["Solution", "pick", "pick", "pick", "pick", "pick"] [[[[-2, -2, 1, 1], [2, 2, 4, 6]]], [], [], [], [], []] Output [null, [1, -2], [1, -1], [-1, -2], [-2, -2], [0, 0]] Explanation Solution solution = new Solution([[-2, -2, 1, 1], [2, 2, 4, 6]]); solution.pick(); // return [1, -2] solution.pick(); // return [1, -1] solution.pick(); // return [-1, -2] solution.pick(); // return [-2, -2] solution.pick(); // return [0, 0]
Constraints:
1 <= rects.length <= 100
rects[i].length == 4
-109 <= ai < xi <= 109
-109 <= bi < yi <= 109
xi - ai <= 2000
yi - bi <= 2000
- All the rectangles do not overlap.
- At most
104
calls will be made topick
.
题目大意:给定一组矩阵,所有矩阵与坐标轴平行并且没有重叠。每个矩阵用4个值表示 rects[i] = [ai, bi, xi, yi],
其中(ai, bi)表示矩阵左下顶点,(xi, yi)表示右上顶点。每个矩阵(包括4条边)都包含一定数量的整数点(横纵坐标都是整数)。现在要你随机地以相等的概率返回任意一个矩阵里的任意一个点。
解题思路:暴力解法就是找出所有矩阵所有的点,把所有点都存入一个一维数组里,然后从0到数组总长度里随机选择一个点,那么每个点就是等概率的。但是要是点的个数太多的话这种解法就会超时超空间。另外一种思路就是先随机选择一个矩阵然后再从选中的矩阵里随机选出一个点,由于矩阵有大有小包含的点数有多有少,如果我们以等概率抽取一个矩阵,那么最后随机抽取的点就不是等概率的。在暴力解法中我们是把所有矩阵的点都映射到一个一维数组上,其实我们不需要映射每一个点,可以把来自同一个矩阵的点用一个区间来表示,每个矩阵区间的权重依矩阵大小(包含点数多少)而定,这使我们不禁想起LeetCode 528. Random Pick with Weight ,两题的解题思路基本相同。
把矩阵点区间映射到从原点开始的一维坐标轴上就可以表示成,第一矩阵:[0, num_1),第二个矩阵[num_1, num_1+num_2), ..., 最后一个矩阵[num_1+num_2 + ...num_n-1, total_num)。 用一个一维数组来表示就是:[num_1, num_1+num_2, ..., num_1+num_2 + ...num_n-1, total_num)。这样从[0, total_num)区间内随机取一个点,找出这个点在数组里的上届upper bound设为i,那么这个点就是落在第i(下标从0开始)个矩阵里。
class Solution:
def __init__(self, rects: List[List[int]]):
self.rects = rects
self.points = []
self.num = 0
for rect in rects:
self.num += (rect[2] - rect[0] + 1) * (rect[3] - rect[1] + 1)
self.points.append(self.num)
def pick(self) -> List[int]:
def upperBound(i):
l, r = 0, len(self.points) - 1
while l <= r:
mid = (l + r) // 2
if i < self.points[mid]:
r = mid - 1
else:
l = mid + 1
return l
i = upperBound(randrange(self.num))
x = randrange(self.rects[i][0], self.rects[i][2] + 1)
y = randrange(self.rects[i][1], self.rects[i][3] + 1)
return [x, y]