1. 程式人生 > 實用技巧 >218. 天際線問題 (JAVA)

218. 天際線問題 (JAVA)

城市的天際線是從遠處觀看該城市中所有建築物形成的輪廓的外部輪廓。現在,假設您獲得了城市風光照片(圖A)上顯示的所有建築物的位置和高度,請編寫一個程式以輸出由這些建築物形成的天際線(圖B)。

每個建築物的幾何資訊用三元組[Li,Ri,Hi] 表示,其中 Li 和 Ri 分別是第 i 座建築物左右邊緣的 x 座標,Hi 是其高度。可以保證0 ≤ Li, Ri ≤ INT_MAX,0 < Hi ≤ INT_MAX 和 Ri - Li > 0。您可以假設所有建築物都是在絕對平坦且高度為 0 的表面上的完美矩形。

例如,圖A中所有建築物的尺寸記錄為:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] 。

輸出是以[ [x1,y1], [x2, y2], [x3, y3], ... ] 格式的“關鍵點”(圖B中的紅點)的列表,它們唯一地定義了天際線。關鍵點是水平線段的左端點。請注意,最右側建築物的最後一個關鍵點僅用於標記天際線的終點,並始終為零高度。此外,任何兩個相鄰建築物之間的地面都應被視為天際線輪廓的一部分。

例如,圖B中的天際線應該表示為:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]。

說明:

任何輸入列表中的建築物數量保證在 [0, 10000]範圍內。
輸入列表已經按左x 座標Li 進行升序排列。
輸出列表必須按 x 位排序。

輸出天際線中不得有連續的相同高度的水平線。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正確的答案;三條高度為 5 的線應該在最終輸出中合併為一個:[...[2 3], [4 5], [12 7], ...]

思路:使用歸併排序,排序的內容就是返回值結構List<List<Integer>>。

class Solution {
    public List<List<Integer>> getSkyline(int[][] buildings) {
        if (buildings.length == 0) return
new ArrayList<>(); return segment(buildings, 0, buildings.length-1); } public List<List<Integer>> segment(int[][] buildings, int l, int r){ List<List<Integer>> resList = new ArrayList<>(); if(l == r){ resList.add(Arrays.asList(buildings[l][0], buildings[l][2])); //左上點 resList.add(Arrays.asList(buildings[l][1], 0)); //右下點 return resList; } int mid = (l + r) >> 1; List<List<Integer>> leftList = segment(buildings, l, mid); List<List<Integer>> rightList = segment(buildings, mid+1, r); //merge int lIndex = 0, rIndex = 0; int lx, ly, rx, ry; int curLeftH = 0, curRightH = 0; //當前左、右List的高度 while(lIndex < leftList.size() || rIndex < rightList.size()) { if (lIndex >= leftList.size()) { resList.add(rightList.get(rIndex++)); } else if(rIndex >= rightList.size()) { resList.add(leftList.get(lIndex++)); } else { lx = leftList.get(lIndex).get(0); ly = leftList.get(lIndex).get(1); rx = rightList.get(rIndex).get(0); ry = rightList.get(rIndex).get(1); //先合併靠左邊的點 if (lx < rx) { //合併lx //判斷應該加入的高度 if(ly > curRightH) { //無論以前的高度是curRigthH還是curLeftH,現在都有新高度ly了(注意ly不可能=curLeftH) resList.add(leftList.get(lIndex)); } else if(curLeftH > curRightH ) { //以前左面比右面高,現在左面比有面矮,所以要把右面的高度加入 resList.add(Arrays.asList(lx, curRightH)); } curLeftH = ly; lIndex++; } else if (lx > rx) {//合併rx if(ry > curLeftH) { resList.add(rightList.get(rIndex)); } else if(curRightH > curLeftH ) { resList.add(Arrays.asList(rx, curLeftH)); } curRightH = ry; rIndex++; } else { //在同一點,一起合併 if(ly >= ry && ly != (curLeftH > curRightH ? curLeftH: curRightH)) { resList.add(leftList.get(lIndex)); } else if (ly <= ry && ry != (curLeftH > curRightH ? curLeftH: curRightH)){ resList.add(rightList.get(rIndex)); } curLeftH = ly; curRightH = ry; lIndex++; rIndex++; } } } return resList; } }