日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

leetcode 218. The Skyline Problem | 218. 天际线问题(线段树)

發(fā)布時(shí)間:2024/2/28 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 leetcode 218. The Skyline Problem | 218. 天际线问题(线段树) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目

https://leetcode-cn.com/problems/the-skyline-problem/

題解

線段樹問題,根據(jù)左神的思路改編,外加我想到的壓縮的 tricks(數(shù)字范圍太大,實(shí)在想不出別的辦法了,一開始是直接把過大的數(shù)除以某個(gè) scale,但是這樣是有損的,無法復(fù)原,于是想到了用 map 存壓縮前后的映射關(guān)系。只要保持壓縮前后的數(shù)字大小順序不變,這個(gè)壓縮就是無損的。)

class Solution {public static final int N = 1 << 15; // 2^15=32768,考慮到 buildings.length <= 10^4,壓縮后總共不超過2*10^4個(gè)橫坐標(biāo)public List<List<Integer>> getSkyline(int[][] buildings) {SegmentTree segmentTree = new SegmentTree(N);// 壓縮(編碼)// 排序,然后映射,因?yàn)椴怀^10000,所以肯定能映射開Set<Integer> set = new TreeSet<>();for (int[] task : buildings) {set.add(task[0]);set.add(task[1]);}Map<Integer, Integer> decodeMap = new HashMap<>();Map<Integer, Integer> encodeMap = new HashMap<>();int cipher = 0;for (int plain : set) {cipher += 2; // 用+2而不是+1,目的是留出地面的間隔,避免兩個(gè)樓挨在一起時(shí),丟失了地面decodeMap.put(cipher, plain);encodeMap.put(plain, cipher);}for (int[] task : buildings) {task[0] = encodeMap.get(task[0]);task[1] = encodeMap.get(task[1]);}// 更新線段樹(核心)for (int[] task : buildings) {segmentTree.update(task[0], task[1], task[2], 0, N, 1); // 把從task[0]到task[1]的位置更新為task[2]}segmentTree.flush();// 打補(bǔ)丁(之前為了方便下標(biāo)索引,線段樹是從1位置開始構(gòu)建的,現(xiàn)在要把0位置也考慮進(jìn)去)segmentTree.max[N - 2] = 0;segmentTree.max[2 * N - 1] = 0;for (int[] task : buildings) {if (task[0] == 0) segmentTree.max[N - 1] = Math.max(segmentTree.max[N - 1], task[2]);}// 構(gòu)造返回值(遍歷所有葉子)List<List<Integer>> result = new ArrayList<>();for (int i = N - 1; i < 2 * N; i++) {if (segmentTree.max[i] != segmentTree.max[i - 1]) {ArrayList<Integer> list = new ArrayList<>();list.add(segmentTree.max[i - 1] < segmentTree.max[i] ? i - N + 1 : i - N);list.add(segmentTree.max[i]);result.add(list);}}// 解碼for (List<Integer> list : result) {list.set(0, decodeMap.get(list.get(0)));}return result;}public static class SegmentTree {private int SIZE;private int[] max;private int[] change;private boolean[] update;public SegmentTree(int N) {SIZE = N + 1;max = new int[SIZE << 2]; // 用來支持腦補(bǔ)概念中,某一個(gè)范圍的累加和信息change = new int[SIZE << 2]; // 用來支持腦補(bǔ)概念中,某一個(gè)范圍有沒有更新操作的任務(wù)update = new boolean[SIZE << 2]; // 用來支持腦補(bǔ)概念中,某一個(gè)范圍是否需要更新(而不是更新成0)}// 之前的所有懶增加、懶更新,從父范圍發(fā)給左右兩個(gè)子范圍,分發(fā)策略是什么private void pushDown(int rt) {if (update[rt]) {update[rt << 1] = true;update[rt << 1 | 1] = true;change[rt << 1] = change[rt];change[rt << 1 | 1] = change[rt];max[rt << 1] = Math.max(max[rt << 1], change[rt]);max[rt << 1 | 1] = Math.max(max[rt << 1 | 1], change[rt]);update[rt] = false;}}// 想要把 L~R 所有的值變成 H// 當(dāng)前影響 l~r,當(dāng)前范圍信息存在數(shù)組的 rt 位置public void update(int L, int R, int H, int l, int r, int rt) {if (L <= l && r <= R) {if (H >= max[rt]) {update[rt] = true;change[rt] = H;max[rt] = H;}return;}// 當(dāng)前任務(wù)躲不掉,無法懶更新,要往下發(fā)一層int mid = (l + r) >> 1;pushDown(rt);if (L <= mid) {update(L, R, H, l, mid, rt << 1);}if (R > mid) {update(L, R, H, mid + 1, r, rt << 1 | 1);}}// 把所有的懶更新都下放到底部,類似于自底向上的堆排序public void flush() {for (int i = max.length - 1; i >= 0; i--) {if (max[i] == 0) heapify(i);}}public int heapify(int i) {if (i == 0) return 0;max[i] = Math.max(max[i], heapify(i / 2));return max[i];}} }

總結(jié)

以上是生活随笔為你收集整理的leetcode 218. The Skyline Problem | 218. 天际线问题(线段树)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。