• [Swift]LeetCode218. 天际线问题 | The Skyline Problem


    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
    ➤微信公众号:山青咏芝(shanqingyongzhi)
    ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
    ➤GitHub地址:https://github.com/strengthen/LeetCode
    ➤原文地址:https://www.cnblogs.com/strengthen/p/10198037.html 
    ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
    ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

    A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skylineformed by these buildings collectively (Figure B).

    Buildings Skyline Contour

    The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi], where Li and Ri are the x coordinates of the left and right edge of the ith building, respectively, and Hi is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX0 < Hi ≤ INT_MAX, and Ri - Li > 0. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.

    For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] .

    The output is a list of "key points" (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ] that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.

    For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ].

    Notes:

    • The number of buildings in any input list is guaranteed to be in the range [0, 10000].
    • The input list is already sorted in ascending order by the left x position Li.
    • The output list must be sorted by the x position.
    • There must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...[2 3], [4 5], [7 5], [11 5], [12 7]...] is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...[2 3], [4 5], [12 7], ...]

    城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)。

    Buildings Skyline Contour

    每个建筑物的几何信息用三元组 [Li,Ri,Hi] 表示,其中 Li 和 Ri分别是第 i 座建筑物左右边缘的 x 坐标,Hi 是其高度。可以保证 0 ≤ Li, Ri ≤ INT_MAX0 < 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], ...]

    264ms

      1 class Solution {
      2     func getSkyline(_ buildings: [[Int]]) -> [[Int]] {
      3         var queue = [[Int]]()
      4         for building in buildings {
      5             let begin = [building[0],building[2]]
      6             let end = [building[1], -building[2]]
      7             queue.append(begin)
      8             queue.append(end)
      9         }
     10         
     11         queue.sort { (nums1, nums2) -> Bool in
     12             if nums1[0] == nums2[0] {
     13                 return nums1[1] > nums2[1]
     14             }
     15             
     16             return nums1[0] < nums2[0]
     17         }
     18         
     19         
     20         var res = [[Int]]()
     21         var heights = Heap(array: [Int](), sort: >)
     22         var removes = Heap(array: [Int](), sort: >)
     23         var pHeight = 0
     24         for line in queue {
     25             let h = line[1]
     26             
     27             if h > 0 {
     28                 if h > pHeight {
     29                     res.append([line[0],h])
     30                 }
     31                 heights.insert(h)
     32                 pHeight = heights.peek()!
     33             }else {
     34                 removes.insert(-h)
     35                 while !heights.isEmpty && !removes.isEmpty && heights.peek()! == removes.peek()! {
     36                     heights.remove()
     37                     removes.remove()
     38                 }
     39                 pHeight = heights.peek() ?? 0
     40                 if -h > pHeight {
     41                     res.append([line[0],pHeight])
     42                 }
     43             }
     44         }
     45         return res
     46     }
     47     
     48     public struct Heap<T> {
     49         var nodes = [T]()
     50         
     51         private var orderCriteria:(T,T) -> Bool
     52         
     53         public init(sort:@escaping (T,T) -> Bool) {
     54             self.orderCriteria = sort
     55         }
     56         
     57         public init(array:[T],sort:@escaping(T, T) -> Bool) {
     58             self.orderCriteria = sort
     59             configureHeap(from:array)
     60         }
     61         
     62         private mutating func configureHeap(from array:[T])  {
     63             nodes = array
     64             for i in stride(from: (nodes.count - 1) / 2, through: 0, by: -1) {
     65                 shiftDown(i)
     66             }
     67         }
     68         
     69         public var isEmpty:Bool {
     70             return nodes.isEmpty
     71         }
     72         
     73         public var count : Int {
     74             return nodes.count
     75         }
     76         
     77         @inline(__always) internal func parentIndex(ofIndex i : Int) -> Int {
     78             return (i - 1) / 2
     79         }
     80         
     81         @inline(__always) internal func leftChildIndex(ofIndex i : Int) -> Int {
     82             return 2 * i + 1
     83         }
     84         
     85         @inline(__always) internal func rightChildIndex(ofIndex i : Int) -> Int {
     86             return 2 * i + 2
     87         }
     88         
     89         public func peek() -> T? {
     90             return nodes.first
     91         }
     92         
     93         public mutating func insert(_ value: T) {
     94             nodes.append(value)
     95             shiftUp(nodes.count - 1)
     96         }
     97         
     98         public mutating func insert<S:Sequence>(_ sequence: S) where S.Iterator.Element == T {
     99             for value in sequence {
    100                 insert(value)
    101             }
    102         }
    103                 
    104         @discardableResult public mutating func remove() -> T? {
    105             guard !isEmpty else {return nil}
    106             if nodes.count == 1 {
    107                 return nodes.removeFirst()
    108             }else {
    109                 let value = nodes[0]
    110                 nodes[0] = nodes.removeLast()
    111                 shiftDown(0)
    112                 return value
    113             }
    114         }
    115         
    116 
    117         @discardableResult public mutating func remove(at index: Int) -> T? {
    118             guard index < count else {return nil}
    119             
    120             let size = nodes.count - 1
    121             if index != count {
    122                 nodes.swapAt(index, size)
    123                 shiftDown(form: index, until: size)
    124                 shiftUp(index)
    125             }
    126             
    127             return nodes.removeLast()
    128             
    129         }
    130         
    131         internal mutating func shiftUp(_ index : Int) {
    132             var childIndex = index
    133             let child = nodes[childIndex]
    134             var parentIndex = self.parentIndex(ofIndex: childIndex)
    135             
    136             while childIndex > 0 && orderCriteria(child, nodes[parentIndex]) {
    137                 nodes[childIndex] = nodes[parentIndex]
    138                 childIndex = parentIndex
    139                 parentIndex = self.parentIndex(ofIndex: childIndex)
    140             }
    141             nodes[childIndex] = child
    142         }
    143         
    144         internal mutating func shiftDown(form index: Int, until endIndex: Int)  {
    145             let leftChildIndex = self.leftChildIndex(ofIndex: index)
    146             let rightChildIndex = leftChildIndex + 1
    147             var first = index
    148             if leftChildIndex < endIndex && orderCriteria(nodes[leftChildIndex], nodes[first]) {
    149                 first = leftChildIndex
    150             }
    151             
    152             if rightChildIndex < endIndex && orderCriteria(nodes[rightChildIndex], nodes[first]) {
    153                 first = rightChildIndex
    154             }
    155             if first == index {return}
    156             nodes.swapAt(index, first)
    157             shiftDown(form: first, until: endIndex)
    158         }
    159         
    160         internal mutating func shiftDown(_ index:Int) {
    161             
    162             shiftDown(form: index, until: nodes.count)
    163         }
    164         
    165     }
    166 }

    676ms

     1 class Solution {
     2   func getSkyline(_ buildings: [[Int]]) -> [[Int]] {
     3     var points: [Int] = []
     4     for building in buildings {
     5       points.append(building[0])
     6       points.append(building[1])
     7     }
     8     points.sort()
     9 
    10     var segs = [Int](repeating: 0, count: points.count)
    11 
    12     var pos = 0
    13     for building in buildings {
    14       // find start point
    15       while points[pos] < building[0] { pos += 1 }
    16       // go to end
    17       var i = pos
    18 
    19       while points[i] < building[1] {
    20         if segs[i] < building[2] {
    21           segs[i] = building[2]
    22         }
    23         i += 1
    24       }
    25     }
    26 
    27     var result: [[Int]] = []
    28     var currHeight = 0
    29     for (index, h) in segs.enumerated() {
    30       if currHeight != h {
    31         result.append([points[index], h])
    32         currHeight = h
    33       }
    34     }
    35 
    36     return result
    37   }
    38 }

    1660ms

      1 class Solution {
      2   public struct PriorityQueue<T: Comparable> {
      3 
      4     fileprivate var heap = [T]()
      5     private let ordered: (T, T) -> Bool
      6 
      7     public init(ascending: Bool = false, startingValues: [T] = []) {
      8       self.init(order: ascending ? { $0 > $1 } : { $0 < $1 }, startingValues: startingValues)
      9     }
     10 
     11     /// Creates a new PriorityQueue with the given ordering.
     12     ///
     13     /// - parameter order: A function that specifies whether its first argument should
     14     ///                    come after the second argument in the PriorityQueue.
     15     /// - parameter startingValues: An array of elements to initialize the PriorityQueue with.
     16     public init(order: @escaping (T, T) -> Bool, startingValues: [T] = []) {
     17       ordered = order
     18 
     19       // Based on "Heap construction" from Sedgewick p 323
     20       heap = startingValues
     21       var i = heap.count/2 - 1
     22       while i >= 0 {
     23         sink(i)
     24         i -= 1
     25       }
     26     }
     27 
     28     /// How many elements the Priority Queue stores
     29     public var count: Int { return heap.count }
     30 
     31     /// true if and only if the Priority Queue is empty
     32     public var isEmpty: Bool { return heap.isEmpty }
     33 
     34     /// Add a new element onto the Priority Queue. O(lg n)
     35     ///
     36     /// - parameter element: The element to be inserted into the Priority Queue.
     37     public mutating func push(_ element: T) {
     38       heap.append(element)
     39       swim(heap.count - 1)
     40     }
     41 
     42     /// Remove and return the element with the highest priority (or lowest if ascending). O(lg n)
     43     ///
     44     /// - returns: The element with the highest priority in the Priority Queue, or nil if the PriorityQueue is empty.
     45     public mutating func pop() -> T? {
     46 
     47       if heap.isEmpty { return nil }
     48       if heap.count == 1 { return heap.removeFirst() }  // added for Swift 2 compatibility
     49       // so as not to call swap() with two instances of the same location
     50       heap.swapAt(0, heap.count - 1)
     51       let temp = heap.removeLast()
     52       sink(0)
     53 
     54       return temp
     55     }
     56 
     57 
     58     /// Removes the first occurence of a particular item. Finds it by value comparison using ==. O(n)
     59     /// Silently exits if no occurrence found.
     60     ///
     61     /// - parameter item: The item to remove the first occurrence of.
     62     public mutating func remove(_ item: T) {
     63       if let index = heap.index(of: item) {
     64         heap.swapAt(index, heap.count - 1)
     65         heap.removeLast()
     66         if index < heap.count { // if we removed the last item, nothing to swim
     67           swim(index)
     68           sink(index)
     69         }
     70       }
     71     }
     72 
     73     /// Removes all occurences of a particular item. Finds it by value comparison using ==. O(n)
     74     /// Silently exits if no occurrence found.
     75     ///
     76     /// - parameter item: The item to remove.
     77     public mutating func removeAll(_ item: T) {
     78       var lastCount = heap.count
     79       remove(item)
     80       while (heap.count < lastCount) {
     81         lastCount = heap.count
     82         remove(item)
     83       }
     84     }
     85 
     86     /// Get a look at the current highest priority item, without removing it. O(1)
     87     ///
     88     /// - returns: The element with the highest priority in the PriorityQueue, or nil if the PriorityQueue is empty.
     89     public func peek() -> T? {
     90       return heap.first
     91     }
     92 
     93     /// Eliminate all of the elements from the Priority Queue.
     94     public mutating func clear() {
     95       heap.removeAll(keepingCapacity: false)
     96     }
     97 
     98     // Based on example from Sedgewick p 316
     99     private mutating func sink(_ index: Int) {
    100       var index = index
    101       while 2 * index + 1 < heap.count {
    102 
    103         var j = 2 * index + 1
    104 
    105         if j < (heap.count - 1) && ordered(heap[j], heap[j + 1]) { j += 1 }
    106         if !ordered(heap[index], heap[j]) { break }
    107 
    108         heap.swapAt(index, j)
    109         index = j
    110       }
    111     }
    112 
    113     // Based on example from Sedgewick p 316
    114     private mutating func swim(_ index: Int) {
    115       var index = index
    116       while index > 0 && ordered(heap[(index - 1) / 2], heap[index]) {
    117         heap.swapAt((index - 1) / 2, index)
    118         index = (index - 1) / 2
    119       }
    120     }
    121   }
    122 
    123   func getSkyline(_ buildings: [[Int]]) -> [[Int]] {
    124     var heights: [(pos: Int, h: Int)] = []
    125     for building in buildings {
    126       heights.append((building[0], -building[2]))
    127       heights.append((building[1], building[2]))
    128     }
    129     heights.sort { (a, b) in
    130       if (a.pos == b.pos) {
    131         return a.h < b.h
    132       } else {
    133         return a.pos < b.pos
    134       }
    135     }
    136 
    137     var heap = PriorityQueue<Int>()
    138     var result: [[Int]] = []
    139     var prev = 0
    140 
    141     heap.push(0)
    142     for h in heights {
    143       if (h.h < 0) {
    144         heap.push(-h.h)
    145       } else {
    146         heap.remove(h.h)
    147       }
    148       if let curr = heap.peek(), prev != curr {
    149         result.append([h.pos, curr])
    150         prev = curr
    151       }
    152     }
    153 
    154     return result
    155   }
    156 }

    1712ms

      1 class PriorityQueue<T> {
      2     private var heap: [T] = [T]()
      3     private let ordered: (T, T) -> Bool
      4 
      5     init(order: @escaping (T, T) -> Bool) {
      6         self.ordered = order
      7     }
      8 
      9     var isEmpty: Bool {
     10         return heap.isEmpty
     11     }
     12     var count: Int {
     13         return heap.count
     14     }
     15 
     16     func push(_ element: T) {
     17         heap.append(element)
     18         swim(heap.count - 1)
     19     }
     20 
     21     func pop() -> T? {
     22         if self.isEmpty {
     23             return nil
     24         }
     25 
     26         if self.heap.count == 1 {
     27             return heap.remove(at: 0)
     28         }
     29 
     30         heap.swapAt(0, heap.count - 1)
     31         let temp = heap.removeLast()
     32         sink(0)
     33         return temp
     34     }
     35 
     36     func peek() -> T? {
     37         if self.isEmpty {
     38             return nil
     39         }
     40 
     41         return self.heap[0]
     42     }
     43 
     44     private func sink(_ index: Int) {
     45         var index = index
     46         while 2 * index + 1 < heap.count {
     47             let leftChildIndex = 2 * index + 1
     48 
     49             var first = index
     50             if leftChildIndex < heap.count && ordered(heap[leftChildIndex], heap[first]) {
     51                 first = leftChildIndex
     52             }
     53 
     54             let rightChildIndex = leftChildIndex + 1
     55             if rightChildIndex < heap.count && ordered(heap[rightChildIndex], heap[first]) {
     56                 first = rightChildIndex
     57             }
     58 
     59             if index == first {
     60                 break
     61             }
     62 
     63             heap.swapAt(index, first)
     64             index = first
     65         }
     66     }
     67 
     68     private func swim(_ index: Int) {
     69         var index = index
     70         while index > 0 && ordered(heap[index], heap[(index - 1) / 2]) {
     71             heap.swapAt((index - 1) / 2, index)
     72             index = (index - 1) / 2
     73         }
     74     }
     75 }
     76 
     77 extension PriorityQueue where T: Comparable {
     78     func remove(_ element: T) {
     79         if let index = heap.index(of: element) {
     80             heap.swapAt(index, heap.count - 1)
     81             heap.removeLast()
     82             if index < heap.count {
     83                 swim(index)
     84                 sink(index)
     85             }
     86         }
     87     }
     88 }
     89 
     90 class Solution {
     91     class Point {
     92         var pos: Int
     93         var height: Int
     94         var isStart: Bool
     95 
     96         init(_ pos: Int, _ height: Int, _ isStart: Bool) {
     97             self.pos = pos
     98             self.height = height
     99             self.isStart = isStart
    100         }
    101     }
    102 
    103     func getSkyline(_ buildings: [[Int]]) -> [[Int]] {
    104         guard buildings.count > 0 && buildings[0].count > 0 else {
    105             return []
    106         }
    107 
    108         var positions = Array(repeating: Point(0, 0, false), count: buildings.count * 2)
    109         for idx in 0 ..< buildings.count {
    110             let start = Point(buildings[idx][0], buildings[idx][2], true)
    111             positions[idx * 2] = start
    112 
    113             let end = Point(buildings[idx][1], buildings[idx][2], false)
    114             positions[idx * 2 + 1] = end
    115         }
    116 
    117         positions.sort { pt1, pt2 in
    118             if pt1.pos != pt2.pos {
    119                 return pt1.pos < pt2.pos
    120             }
    121 
    122             if pt1.isStart && pt2.isStart {
    123                 return pt1.height > pt2.height
    124             }
    125 
    126             if !pt1.isStart && !pt2.isStart {
    127                 return pt1.height < pt2.height
    128             }
    129 
    130             return pt1.isStart
    131          }
    132 
    133         let queue = PriorityQueue<Int>(order: >)
    134         queue.push(0)
    135 
    136         var result: [[Int]] = []
    137         var preMaxVal = 0
    138         for point in positions {
    139             if point.isStart {
    140                 queue.push(point.height)
    141                 let curMaxVal = queue.peek()!
    142                 if curMaxVal > preMaxVal {
    143                     result.append([point.pos, point.height])
    144                     preMaxVal = curMaxVal
    145                 }
    146             } else {
    147                 queue.remove(point.height)
    148                 let curMaxVal = queue.peek()!
    149                 if curMaxVal < preMaxVal {
    150                     result.append([point.pos, curMaxVal])
    151                     preMaxVal = curMaxVal
    152                 }
    153             }
    154         }
    155 
    156         return result
    157     }
    158 }

    1916ms

     1 class Solution {
     2     func getSkyline(_ buildings: [[Int]]) -> [[Int]] {
     3         if buildings.count == 0 {
     4             return []   
     5         }
     6         if buildings.count == 1 {
     7             let b = buildings[0]
     8             let x1 = b[0]; let x2 = b[1]; let y = b[2]
     9             return [[x1, y], [x2, 0]]
    10         }
    11         var bsplit: [(Int, Int, Bool)] = []
    12         for b in buildings {
    13             let x1 = b[0]; let x2 = b[1]; let y = b[2]
    14             bsplit.append((x1, y, false))
    15             bsplit.append((x2, y, true))            
    16         }
    17         // TODO replace h with priority queue
    18         var h: [(Int, Int)] = []    
    19         let s1: ((Int, Int), (Int, Int)) -> Bool = {
    20             $0.1 > $1.1 
    21             || ($0.1 == $1.1 && $0.0 > $0.1)            
    22         }
    23         let so: ((Int, Int, Bool), (Int, Int, Bool)) -> Bool = {
    24             $0.0 < $1.0 
    25             || ($0.0 == $1.0 && $0.2 == false && $1.2 == true)
    26             || ($0.0 == $1.0 && $0.1 > $1.1)            
    27         }
    28         let buildingsSorted = bsplit.sorted(by: so)
    29 //        print("buildingsSorted (buildingsSorted)")
    30         var ans: [[Int]] = []
    31         for i in 0..<buildingsSorted.count {
    32             let b = buildingsSorted[i]
    33             let bx = b.0; let by = b.1; let close = b.2 == true
    34 //            print("b (b) h (h)")
    35             if h.count == 0 {
    36                 h.append((bx, by))
    37                 ans.append([bx, by])
    38                 continue
    39             }
    40             if close {
    41                 if let index = h.firstIndex(where: {$0.1 == by}) {
    42                     h.remove(at: index)
    43                     if h.count == 0 { ans.append([bx, 0]) }
    44                     if let l = h.first {
    45                         if l.1 < by { ans.append([bx, l.1]) }
    46                     }
    47                 }
    48                 continue
    49             }
    50     //        print("b (b) h (h)")
    51             if let l = h.first {
    52                 if l.1 < by { ans.append([bx, by]) }
    53 //                print("l.1 (l.1) by (by) x3 ans (ans)")
    54             }
    55             if let index = h.firstIndex(where: { $0.1 < by }) {
    56                 h.insert((bx, by), at:index)                
    57             } else {
    58                 h.append((bx, by))            
    59             }
    60             /*
    61             h.append((bx, by))
    62             h.sort(by: s1) // need to optimize???
    63             */
    64 //            print("hx (h)")
    65         }
    66 //        print("ans (ans)")
    67         var i = 1
    68         while i < ans.count {
    69 //            print("i (i) ans (ans)")
    70             if ans[i][0] == ans[i-1][0] {
    71                 ans.remove(at: i - 1)
    72                 continue
    73             }
    74             i += 1
    75         }
    76         return ans
    77     }
    78 }
  • 相关阅读:
    【JDK】:java.lang.Integer源码解析
    使用truelicense实现用于JAVA工程license机制(包括license生成和验证)
    Android Button.getWidth()为0的问题
    nacos启动报错nacos Unable to start web server;
    Oracle字符集相关学习笔记记录
    Oracle触发器简单使用记录
    Oracle分析函数、窗口函数简单记录汇总
    Oracle远程数据建物化视图(materialized)创建简单记录,以及DBLINK的创建
    Oracle 行列转换函数pivot、unpivot的使用(二)
    Oracle递归查询(start with…connect by prior)
  • 原文地址:https://www.cnblogs.com/strengthen/p/10198037.html
Copyright © 2020-2023  润新知