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.html
Note:app
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.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.Example 1:dom
Input:
["Solution","pick","pick","pick"]
[[[[1,1,5,5]]],[],[],[]] Output: [null,[4,1],[4,1],[3,3]]
Example 2:post
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.spa
这道题给了咱们一些非重叠的矩形,让咱们返回一个这些矩形中的一个随机的点。那么博主的第一直觉就是首先要在这些矩形中随机挑出来一个,而后在这个随机的矩形中再随机生成一个点,经过随机生成一个长和宽便可。博主最开始想到的方法是用rand随机生成一个 [0, n) 范围内的数字,n为输入矩形的个数,这样就获得了一个随机的矩形。可是这种方法貌似行不通,会跪在一个很长的输入测试数据。这使得博主比较困惑了,没有想出缘由是为什么,有哪位看官大神们知道的,麻烦留言告知博主哈!哈,已经知道了,参见评论区二楼留言~ 论坛上的解法有一种是用水塘抽样Reservoir Sampling的方法的,LeetCode以前有过几道须要用这种方法的题目 Random Pick Index,Shuffle an Array 和 Linked List Random Node。这里咱们使用其来随机出一个矩形,作法是遍历全部的矩形,用变量sumArea来计算当前遍历过的全部矩形面积之和,而后变量area是当前遍历的矩形的面积(注意这里不是严格意义上的面积,而是该区域内整数坐标的点的个数,因此长宽相乘的时候都要加1),而后咱们在当前全部矩形面积之和内随机生成一个值,若是这个值小于area,那么选择当前的矩阵为随机矩形。这里至关于一个大小为area的水塘,在这个值以内的话,就更换selected。这个方法是没啥问题,可是博主仍是没想通为啥不能直接随机生成矩形的index。当咱们拿到随机矩形后,以后就随机出宽和高返回便可,参见代码以下:code
解法一:orm
class Solution { public: Solution(vector<vector<int>> rects) { _rects = rects; } vector<int> pick() { int sumArea = 0; vector<int> selected; for (auto rect : _rects) { int area = (rect[2] - rect[0] + 1) * (rect[3] - rect[1] + 1); sumArea += area; if (rand() % sumArea < area) selected = rect; } int x = rand() % (selected[2] - selected[0] + 1) + selected[0]; int y = rand() % (selected[3] - selected[1] + 1) + selected[1]; return {x, y}; } private: vector<vector<int>> _rects; };
这道题在论坛上的主流解法实际上是这个,咱们用TreeMap来创建当前遍历过的矩形面积之和跟该矩形位置之间的映射。而后当咱们求出全部的矩形面积之和后,咱们随机生成一个值,而后在TreeMap中找到第一个大于这个值的矩形,这里博主仍是有疑问,为啥不能直接随机矩形的位置,而是非要跟面积扯上关系。以后的步骤就跟上面的没啥区别了,参见代码以下:htm
解法二:blog
class Solution { public: Solution(vector<vector<int>> rects) { _rects = rects; _totalArea = 0; for (auto rect : rects) { _totalArea += (rect[2] - rect[0] + 1) * (rect[3] - rect[1] + 1); _areaToIdx.insert({_totalArea, _areaToIdx.size()}); } } vector<int> pick() { int val = rand() % _totalArea; int idx = _areaToIdx.upper_bound(val)->second; int width = _rects[idx][2] - _rects[idx][0] + 1; int height = _rects[idx][3] - _rects[idx][1] + 1; return {rand() % width + _rects[idx][0], rand() % height + _rects[idx][1]}; } private: vector<vector<int>> _rects; int _totalArea; map<int, int> _areaToIdx; };
相似题目:
Generate Random Point in a Circle
参考资料:
https://leetcode.com/problems/random-point-in-non-overlapping-rectangles/