LeetCode 497. Random Point in Non-overlapping Rectangles - 二分查找(Binary Search)系列题25

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 rectangles rects.
  • 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 to pick.

题目大意:给定一组矩阵,所有矩阵与坐标轴平行并且没有重叠。每个矩阵用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_1num_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]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值