leetcode497 - Random Point in Non-overlapping Rectangles - medium

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:
1. An integer point is a point that has integer coordinates.
2. A point on the perimeter of a rectangle is included in the space covered by the rectangles.
3. 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.
4. length and width of each rectangle does not exceed 2000.
5. 1 <= rects.length <= 100
6. pick return a point as an array of integer coordinates [p_x, p_y]
7. pick is called at most 10000 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]]
 
 
1.trivial solution. 一开始建立好所有可能的点,然后用O(1) pick其中一个点。 但不现实,如果给的一个长方形面积特别大,那你一开始建立所有点用的memory就爆炸了。
2.先根据面积作为权重,按概率选到长方形。之后在这个长方形的范围内随机选x和y,输出。
 
本题相关:Random Pick with Weight:  https://www.cnblogs.com/jasminemzy/p/9741839.html
 
实现:
class Solution {
    
    private int[][] rects;
    private Random rd;
    private int[] sum;
    private int total;
    
    public Solution(int[][] rects) {
        this.rects = rects;
        this.rd = new Random();
        int[] weight = new int[rects.length];
        for (int i = 0; i < rects.length; i++) {
            weight[i] = (rects[i][2] - rects[i][0] + 1) * (rects[i][3] - rects[i][1] + 1);
        }
        this.sum = new int[weight.length];
        this.total = 0;
        for (int i = 0; i < sum.length; i++) {
            total += weight[i];
            sum[i] = total;
        }
    }
    
    public int[] pick() {
        int[] rect = rects[pickRect()];
        int x = rect[0] + rd.nextInt(rect[2] - rect[0] + 1);
        int y = rect[1] + rd.nextInt(rect[3] - rect[1] + 1);
        return new int[] {x, y};
    }
    
    private int pickRect() {
        int target = rd.nextInt(total);
        int i = 0, j = sum.length - 1;
        while (i < j) {
            int mid = (i + j) / 2;
            if (sum[mid] > target) {
                j = mid;
            } else {
                i = mid + 1;
            }
        }
        return i;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(rects);
 * int[] param_1 = obj.pick();
 */

 

posted @ 2018-10-04 11:19  jasminemzy  阅读(559)  评论(0编辑  收藏  举报