1. 程式人生 > >[Swift]LeetCode480. 滑動窗口中位數 | Sliding Window Median

[Swift]LeetCode480. 滑動窗口中位數 | Sliding Window Median

tor inter struct lee 每次 onf original tuples mem

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples:

[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Given an array nums, there is a sliding window of size k

which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Your job is to output the median array for each window in the original array.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k

= 3.

Window position                Median
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7       -1
 1  3 [-1  -3  5] 3  6  7       -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6

Therefore, return the median sliding window as [1,-1,-1,3,5,6]

.

Note:
You may assume k is always valid, ie: k is always smaller than input array‘s size for non-empty array.


中位數是有序序列最中間的那個數。如果序列的大小是偶數,則沒有最中間的數;此時中位數是最中間的兩個數的平均數。

例如:

[2,3,4],中位數是 3

[2,3],中位數是 (2 + 3) / 2 = 2.5

給出一個數組 nums,有一個大小為 k 的窗口從最左端滑動到最右端。窗口中有 k 個數,每次窗口移動 1 位。你的任務是找出每次窗口移動後得到的新窗口中元素的中位數,並輸出由它們組成的數組。

例如:

給出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。

窗口位置                      中位數
---------------               -----
[1  3  -1] -3  5  3  6  7       1
 1 [3  -1  -3] 5  3  6  7       -1
 1  3 [-1  -3  5] 3  6  7       -1
 1  3  -1 [-3  5  3] 6  7       3
 1  3  -1  -3 [5  3  6] 7       5
 1  3  -1  -3  5 [3  6  7]      6

因此,返回該滑動窗口的中位數數組 [1,-1,-1,3,5,6]

提示:
假設k是合法的,即:k 始終小於輸入的非空數組的元素個數.


408ms

 1 class Solution {
 2     func medianSlidingWindow(_ nums: [Int], _ k: Int) -> [Double] {
 3         guard nums.count >= k else {
 4             return []
 5         }
 6         
 7         var result = [Double]()
 8         result.reserveCapacity(nums.count - k + 1)
 9         var window = nums[0..<k].sorted()
10         for i in 0..<(nums.count - k + 1) {
11             if i > 0 {
12                 window.insertOrdered(nums[i - 1 + k])
13             }
14             result.append(window.median)
15             window.remove(nums[i])
16         }
17         
18         return result
19     }
20 }
21 
22 extension Array where Element == Int {
23     var median: Double {
24         return (Double(self[(count - 1) / 2]) + Double(self[(count) / 2])) / 2
25     }
26     
27     mutating func insertOrdered(_ val: Int) {
28         for i in 0..<count {
29             if self[i] > val {
30                 self.insert(val, at: i)
31                 return
32             }
33         }
34         append(val)
35     }
36     
37     mutating func remove(_ val: Int) {
38         for i in 0..<count {
39             if self[i] == val {
40                 self.remove(at: i)
41                 return
42             }
43         }
44     }
45 }

Runtime: 492 ms Memory Usage: 20.3 MB
 1 class Solution {
 2     func medianSlidingWindow(_ nums: [Int], _ k: Int) -> [Double] {
 3         var k = k
 4         var res:[Double] = [Double]()
 5         var record:[(Int,Int)] = [(Int,Int)]()
 6         for i in 0..<k
 7         {
 8             record.append((nums[i],i))
 9         }
10         record.sort(by: cmp)
11         update(&res, &record, &k)
12         for i in k..<nums.count
13         {
14             record.remove(at: beforePos(&record, i - k))
15             record.insert((nums[i],i), at: binPos(&record, nums[i]))
16             update(&res, &record, &k)
17         }
18         return res
19     }
20     
21     func cmp(_ a:(Int,Int),_ b:(Int,Int)) -> Bool
22     {
23         if a.0 == b.0 {return a.1 < b.1}
24         return a.0 < b.0
25     }
26     
27     func binPos(_ record:inout [(Int,Int)],_ target:Int) -> Int
28     {
29         var left:Int = 0
30         var right:Int = record.count
31         while(left < right)
32         {
33             let middle:Int = left + (right - left) / 2
34             if record[ middle].0 == target
35             {
36                 return middle
37             }
38             else if record[ middle].0 < target
39             {
40                 left = middle + 1
41             }
42             else
43             {
44                 right = middle
45             }
46         }
47         return left
48     }
49     
50     func beforePos(_ record:inout [(Int,Int)],_ j:Int) -> Int
51     {
52         for i in 0..<record.count
53         {
54             if record[i].1 == j
55             {
56                 return i
57             }
58         }
59         return 0
60     }
61     
62     func update(_ res:inout [Double],_ record:inout [(Int,Int)],_ k:inout Int )
63     {
64         if k % 2 == 1
65         {
66             res.append(Double(record[ record.count / 2].0))
67         }
68         else
69         {
70             res.append(Double(record[ record.count / 2].0) * 1.0 / 2 + Double(record[ record.count/2-1].0) * 1.0 / 2)
71         }
72     }
73 }

636ms

  1 class Solution {
  2     var maxHeap = Heap<Int>(sort: >)
  3 var minHeap = Heap<Int>(sort: <)
  4 
  5 func medianSlidingWindow(_ nums: [Int], _ k: Int) -> [Double] {
  6     var res = [Double]()
  7     
  8     for (index, value) in nums.enumerated() {
  9         if maxHeap.isEmpty || value <= maxHeap.peek()! {
 10             maxHeap.insert(value)
 11         } else {
 12             minHeap.insert(value)
 13         }
 14         
 15         balance()
 16         
 17         let removeTarget = index - k
 18         if removeTarget >= 0 {
 19             if nums[removeTarget] > maxHeap.peek()! {
 20                 minHeap.remove(node: nums[removeTarget])
 21             } else {
 22                 maxHeap.remove(node: nums[removeTarget])
 23             }
 24         }
 25         
 26         balance()
 27         
 28         if index >= k - 1 {
 29             if k % 2 == 0 {
 30                 res.append((Double(minHeap.peek()!) + Double(maxHeap.peek()!)) / 2)
 31             } else {
 32                 res.append(Double(maxHeap.peek()!))
 33             }
 34         }
 35     }
 36     
 37     return res
 38 }
 39 
 40 func balance() {
 41     while maxHeap.count < minHeap.count {
 42         maxHeap.insert(minHeap.remove()!)
 43     }
 44     
 45     while minHeap.count < maxHeap.count - 1 {
 46         minHeap.insert(maxHeap.remove()!)
 47     }
 48   }
 49 }
 50 
 51 
 52 ////// swfit heap:
 53 public struct Heap<T> {
 54     /** The array that stores the heap‘s nodes. */
 55     var nodes = [T]()
 56     
 57     /**
 58      * Determines how to compare two nodes in the heap.
 59      * Use ‘>‘ for a max-heap or ‘<‘ for a min-heap,
 60      * or provide a comparing method if the heap is made
 61      * of custom elements, for example tuples.
 62      */
 63     private var orderCriteria: (T, T) -> Bool
 64     
 65     /**
 66      * Creates an empty heap.
 67      * The sort function determines whether this is a min-heap or max-heap.
 68      * For comparable data types, > makes a max-heap, < makes a min-heap.
 69      */
 70     public init(sort: @escaping (T, T) -> Bool) {
 71         orderCriteria = sort
 72     }
 73     
 74     /**
 75      * Creates a heap from an array. The order of the array does not matter;
 76      * the elements are inserted into the heap in the order determined by the
 77      * sort function. For comparable data types, ‘>‘ makes a max-heap,
 78      * ‘<‘ makes a min-heap.
 79      */
 80     public init(array: [T], sort: @escaping (T, T) -> Bool) {
 81         orderCriteria = sort
 82         configureHeap(from: array)
 83     }
 84     
 85     /**
 86      * Configures the max-heap or min-heap from an array, in a bottom-up manner.
 87      * Performance: This runs pretty much in O(n).
 88      */
 89     private mutating func configureHeap(from array: [T]) {
 90         nodes = array
 91         for i in stride(from: (nodes.count / 2 - 1), through: 0, by: -1) {
 92             shiftDown(i)
 93         }
 94     }
 95     
 96     public var isEmpty: Bool {
 97         return nodes.isEmpty
 98     }
 99     
100     public var count: Int {
101         return nodes.count
102     }
103     
104     /**
105      * Returns the index of the parent of the element at index i.
106      * The element at index 0 is the root of the tree and has no parent.
107      */
108     @inline(__always) internal func parentIndex(ofIndex i: Int) -> Int {
109         return (i - 1) / 2
110     }
111     
112     /**
113      * Returns the index of the left child of the element at index i.
114      * Note that this index can be greater than the heap size, in which case
115      * there is no left child.
116      */
117     @inline(__always) internal func leftChildIndex(ofIndex i: Int) -> Int {
118         return 2 * i + 1
119     }
120     
121     /**
122      * Returns the index of the right child of the element at index i.
123      * Note that this index can be greater than the heap size, in which case
124      * there is no right child.
125      */
126     @inline(__always) internal func rightChildIndex(ofIndex i: Int) -> Int {
127         return 2 * i + 2
128     }
129     
130     /**
131      * Returns the maximum value in the heap (for a max-heap) or the minimum
132      * value (for a min-heap).
133      */
134     public func peek() -> T? {
135         return nodes.first
136     }
137     
138     /**
139      * Adds a new value to the heap. This reorders the heap so that the max-heap
140      * or min-heap property still holds. Performance: O(log n).
141      */
142     public mutating func insert(_ value: T) {
143         nodes.append(value)
144         shiftUp(nodes.count - 1)
145     }
146     
147     /**
148      * Adds a sequence of values to the heap. This reorders the heap so that
149      * the max-heap or min-heap property still holds. Performance: O(log n).
150      */
151     public mutating func insert<S: Sequence>(_ sequence: S) where S.Iterator.Element == T {
152         for value in sequence {
153             insert(value)
154         }
155     }
156     
157     /**
158      * Allows you to change an element. This reorders the heap so that
159      * the max-heap or min-heap property still holds.
160      */
161     public mutating func replace(index i: Int, value: T) {
162         guard i < nodes.count else { return }
163         
164         remove(at: i)
165         insert(value)
166     }
167     
168     /**
169      * Removes the root node from the heap. For a max-heap, this is the maximum
170      * value; for a min-heap it is the minimum value. Performance: O(log n).
171      */
172     @discardableResult public mutating func remove() -> T? {
173         guard !nodes.isEmpty else { return nil }
174         
175         if nodes.count == 1 {
176             return nodes.removeLast()
177         } else {
178             // Use the last node to replace the first one, then fix the heap by
179             // shifting this new first node into its proper position.
180             let value = nodes[0]
181             nodes[0] = nodes.removeLast()
182             shiftDown(0)
183             return value
184         }
185     }
186     
187     /**
188      * Removes an arbitrary node from the heap. Performance: O(log n).
189      * Note that you need to know the node‘s index.
190      */
191     @discardableResult public mutating func remove(at index: Int) -> T? {
192         guard index < nodes.count else { return nil }
193         
194         let size = nodes.count - 1
195         if index != size {
196             nodes.swapAt(index, size)
197             shiftDown(from: index, until: size)
198             shiftUp(index)
199         }
200         return nodes.removeLast()
201     }
202     
203     /**
204      * Takes a child node and looks at its parents; if a parent is not larger
205      * (max-heap) or not smaller (min-heap) than the child, we exchange them.
206      */
207     internal mutating func shiftUp(_ index: Int) {
208         var childIndex = index
209         let child = nodes[childIndex]
210         var parentIndex = self.parentIndex(ofIndex: childIndex)
211         
212         while childIndex > 0 && orderCriteria(child, nodes[parentIndex]) {
213             nodes[childIndex] = nodes[parentIndex]
214             childIndex = parentIndex
215             parentIndex = self.parentIndex(ofIndex: childIndex)
216         }
217         
218         nodes[childIndex] = child
219     }
220     
221     /**
222      * Looks at a parent node and makes sure it is still larger (max-heap) or
223      * smaller (min-heap) than its childeren.
224      */
225     internal mutating func shiftDown(from index: Int, until endIndex: Int) {
226         let leftChildIndex = self.leftChildIndex(ofIndex: index)
227         let rightChildIndex = leftChildIndex + 1
228         
229         // Figure out which comes first if we order them by the sort function:
230         // the parent, the left child, or the right child. If the parent comes
231         // first, we‘re done. If not, that element is out-of-place and we make
232         // it "float down" the tree until the heap property is restored.
233         var first = index
234         if leftChildIndex < endIndex && orderCriteria(nodes[leftChildIndex], nodes[first]) {
235             first = leftChildIndex
236         }
237         if rightChildIndex < endIndex && orderCriteria(nodes[rightChildIndex], nodes[first]) {
238             first = rightChildIndex
239         }
240         if first == index { return }
241         
242         nodes.swapAt(index, first)
243         shiftDown(from: first, until: endIndex)
244     }
245     
246     internal mutating func shiftDown(_ index: Int) {
247         shiftDown(from: index, until: nodes.count)
248     }
249 }
250 
251 // MARK: - Searching
252 
253 extension Heap where T: Equatable {
254     /** Get the index of a node in the heap. Performance: O(n). */
255     public func index(of node: T) -> Int? {
256         return nodes.index(where: { $0 == node })
257     }
258     
259     /** Removes the first occurrence of a node from the heap. Performance: O(n log n). */
260     @discardableResult public mutating func remove(node: T) -> T? {
261         if let index = index(of: node) {
262             return remove(at: index)
263         }
264         return nil
265     }
266 }

[Swift]LeetCode480. 滑動窗口中位數 | Sliding Window Median