|
| 1 | +# Time: O(logn) |
| 2 | +# Space: O(n) |
| 3 | + |
| 4 | +# Given a list of non-overlapping axis-aligned rectangles rects, |
| 5 | +# write a function pick which randomly and uniformily picks |
| 6 | +# an integer point in the space covered by the rectangles. |
| 7 | +# |
| 8 | +# Note: |
| 9 | +# - An integer point is a point that has integer coordinates. |
| 10 | +# - A point on the perimeter of a rectangle is included in the space covered by the rectangles. |
| 11 | +# - ith rectangle = rects[i] = [x1,y1,x2,y2], |
| 12 | +# where [x1, y1] are the integer coordinates of the bottom-left corner, |
| 13 | +# and [x2, y2] are the integer coordinates of the top-right corner. |
| 14 | +# - length and width of each rectangle does not exceed 2000. |
| 15 | +# - 1 <= rects.length <= 100 |
| 16 | +# - pick return a point as an array of integer coordinates [p_x, p_y] |
| 17 | +# - pick is called at most 10000 times. |
| 18 | +# |
| 19 | +# Example 1: |
| 20 | +# |
| 21 | +# Input: |
| 22 | +# ["Solution","pick","pick","pick"] |
| 23 | +# [[[[1,1,5,5]]],[],[],[]] |
| 24 | +# Output: |
| 25 | +# [null,[4,1],[4,1],[3,3]] |
| 26 | +# Example 2: |
| 27 | +# |
| 28 | +# Input: |
| 29 | +# ["Solution","pick","pick","pick","pick","pick"] |
| 30 | +# [[[[-2,-2,-1,-1],[1,0,3,0]]],[],[],[],[],[]] |
| 31 | +# Output: |
| 32 | +# [null,[-1,-2],[2,0],[-2,-1],[3,0],[-2,-2]] |
| 33 | +# Explanation of Input Syntax: |
| 34 | +# |
| 35 | +# The input is two lists: the subroutines called and their arguments. |
| 36 | +# Solution's constructor has one argument, |
| 37 | +# the array of rectangles rects. pick has no arguments. |
| 38 | +# Arguments are always wrapped with a list, even if there aren't any. |
| 39 | + |
| 40 | +import random |
| 41 | +import bisect |
| 42 | + |
| 43 | + |
| 44 | +class Solution(object): |
| 45 | + |
| 46 | + def __init__(self, rects): |
| 47 | + """ |
| 48 | + :type rects: List[List[int]] |
| 49 | + """ |
| 50 | + self.__rects = list(rects) |
| 51 | + self.__prefix_sum = map(lambda x : (x[2]-x[0]+1)*(x[3]-x[1]+1), rects) |
| 52 | + for i in xrange(1, len(self.__prefix_sum)): |
| 53 | + self.__prefix_sum[i] += self.__prefix_sum[i-1] |
| 54 | + |
| 55 | + def pick(self): |
| 56 | + """ |
| 57 | + :rtype: List[int] |
| 58 | + """ |
| 59 | + target = random.randint(0, self.__prefix_sum[-1]-1) |
| 60 | + left = bisect.bisect_right(self.__prefix_sum, target) |
| 61 | + rect = self.__rects[left] |
| 62 | + width = rect[2]-rect[0]+1 |
| 63 | + height = rect[3]-rect[1]+1 |
| 64 | + base = self.__prefix_sum[left]-width*height |
| 65 | + return [rect[0]+(target-base)%width, rect[1]+(target-base)//width] |
| 66 | + |
| 67 | + |
| 68 | +# Your Solution object will be instantiated and called as such: |
| 69 | +# obj = Solution(rects) |
| 70 | +# param_1 = obj.pick() |
0 commit comments