周賽290。這題難度大概也接近hard了,難點在於測資大小的分析,實作起來並不會太複雜。

題目

輸入二維陣列rectangles代表各長方形的寬和高,二維陣列points代表好幾個座標點。
每個長方形i的左下角座標都在(0,0),而右上角座標為rectangles[i]。
求每個點points[i]被多少長方形覆蓋住。若點在某長方形的邊上,也算是被覆蓋住。

Input: rectangles = [[1,2],[2,3],[2,5]], points = [[2,1],[1,4]]
點(2,1)被長方形(2,3),(2,5)覆蓋
點(1,4)被長方形(2,5)覆蓋
答案為[2,1]

解法

乍看之下沒什麼可以偷工減料的地方,因為某個點要被正方形覆蓋的話,一定要長寬都足夠大,只靠排序沒辦法簡單做到。
測資寫到x<=10^9,但是y<=100,就覺得是很明顯的提示,要我們以高度將長方形分組,之後以二分搜檢查每個高度,這樣最多只要100(log 510^4)而已,還算可以接受。

遍歷所有長方形(l,h),先以高度h分組,將寬度l加入雜湊表中。將所有有效的高度排序存為ks,也將所有高度的組別排序。
處理完後,雜湊表d應會是照著高低出現,然後每個高度h的長方形寬度依序列出,例:

rectangles = [[1,1],[2,2],[3,3],[3,5],[1,2]]
排序好的高度ks = [1,2,3,5]
高度為1的長方形寬度 = [1]
高度為2的長方形寬度 = [1,2]
高度為3的長方形寬度 = [3]
高度為5的長方形寬度 = [3]

之後對於每個點(x,y),只要在雜湊表中對大於等於y的高度k做二分搜,找到每個k有多少寬度大於等於x的長方形。
延續上面的例子,若要找點(1,2)被多少長方形覆蓋:

只要找高度大於等於2的長方形
高度為2,且寬度大於等於1的有[1,2]
高度為3,且寬度大於等於1的有[3]
高度為5,且寬度大於等於1的有[3]
答案應為4

最後解釋一下,對每個d[k]找第一個大於等於x的索引位置i,d[k]大小為N,則i~N-1都是大於x的長方形,故數量為N-i。

class Solution:
    def countRectangles(self, rectangles: List[List[int]], points: List[List[int]]) -> List[int]:
        N=len(rectangles)
        d=defaultdict(list) # group by height
        for l,h in rectangles:
            d[h].append(l)
            
        for k in d:
            d[k]=sorted(d[k])

        ks=sorted(d.keys())
        ans=[]
        for x,y in points:
            cnt=0
            for k in ks:
                if k<y:
                    continue
                cnt+=len(d[k])-(bisect_left(d[k],x))
            ans.append(cnt)
            
        return ans