前K个高频元素3种解题方法

2020-11-17  本文已影响0人  LonnieQ

题目

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

提示:

你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
你可以按任意顺序返回答案。

方法一 优先队列

Swift代码

final class FixedSizePriorityQueue<Element> {
    
    let capacity: Int
    
    fileprivate(set) var count: Int
    
    var isEmpty: Bool { count == 0 }
    
    private var pq, qp: [Int]
    
    var elements: [Element?]
    
    let comparator: ((Element, Element)-> Bool)
    
    public init(_ capacity: Int, comparator: @escaping ((Element, Element)-> Bool)) {
        self.capacity = capacity
        count = 0
        pq = Array(repeating: 0, count: capacity + 1)
        qp = Array(repeating: -1, count: capacity + 1)
        elements = Array(repeating: nil, count: capacity + 1)
        self.comparator = comparator
    }
    
    public func contains(_ i: Int) -> Bool {
        return qp[i] != -1
    }
    
    public func insert(_ i: Int, _ element: Element) {
        count += 1
        qp[i] = count
        pq[count] = i
        elements[i] = element
        swim(count)
    }
    
    public func topIndex() -> Int {
        return pq[1]
    }
    
    public func topElement() -> Element? {
        return elementOf(topIndex())
    }
    
    public func deleteTop() -> Element? {
        if isEmpty {
            return nil
        }
        let element = topElement()
        let min = pq[1]
        exchange(1, count)
        count -= 1
        sink(1)
        qp[min] = -1
        elements[min] = nil
        pq[count + 1] = -1
        return element
    }
    
    public func elementOf(_ i: Int) -> Element? {
        return elements[i]
    }
    
    public func changeKey(_ i: Int, _ key: Element) {
        elements[i] = key
        swim(qp[i])
        sink(qp[i])
    }
    
    public func compare(_ i: Int, _ j: Int) -> Bool {
        return comparator(elements[pq[i]]!, elements[pq[j]]!)
    }
    
    public func delete(_ i: Int) {
        let index = qp[i]
        exchange(index, count)
        count -= 1
        swim(index)
        sink(index)
        elements[i] = nil
        qp[i] = -1
    }
    
    public func exchange(_ i: Int, _ j: Int) {
        pq.swapAt(i, j)
        qp[pq[i]] = i
        qp[pq[j]] = j
    }
    
    private func swim(_ k: Int) {
        var k = k
        while k > 1 && compare(k >> 1, k) {
            pq.swapAt(k >> 1, k)
            k >>= 1
        }
    }

    private func sink(_ k: Int) {
        var k = k, j = k << 1
        while j <= count {
            if j < count && compare(j, j + 1) { j += 1 }
            if !compare(k, j) { break }
            pq.swapAt(k, j)
            k = j
            j = k << 1
        }
    }
    
}

class Solution {
    func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] {
    var dic = [Int: Int]()
    for item in nums {
        if let value = dic[item] {
            dic[item] = value + 1
        } else {
            dic[item] = 1
        }
    }
    let queue = FixedSizePriorityQueue<(Int, Int)>(dic.count, comparator: { $0.1 < $1.1 })
    for item in dic.enumerated() {
        queue.insert(item.offset, item.element)
    }
    var result = [Int]()
    while result.count < k && queue.count > 0 {
        result.append(queue.deleteTop()!.0)
    }
    
    return result
}
}

方法二 红黑树

Swift代码

class RedBlackTree<Key: Comparable, Value> {
    
    final class Node {
        
        public var item: (Key, Value)
        
        public var left: Node?
        
        public var right: Node?
        
        public var count: Int
        
        public var color: Color
        
        public init(
            key: Key,
            value: Value,
            left: Node? = nil,
            right: Node? = nil,
            count: Int = 1,
            color: Color = .red
        ) {
            self.item = (key, value)
            self.left = left
            self.right = right
            self.count = count
            self.color = color
        }
        
        public func rotateLeft() -> Node? {
            guard let x = right else {
                return nil
            }
            right = x.left
            x.left = self
            x.color = x.left?.color ?? .black
            x.left?.color = .red
            x.count = count
            count = (left?.count ?? 0) + (right?.count ?? 0) + 1
            return x
        }
        
        public func rotateRight() -> Node? {
            guard let x = left else {
                return nil
            }
            left = x.right
            x.right = self
            x.color = x.right?.color ?? .black
            x.right?.color = .red
            x.count = count
            count = (left?.count ?? 0) + (right?.count ?? 0) + 1
            return x
        }
        
        public func flipColors() {
            color.toggle()
            left?.color.toggle()
            right?.color.toggle()
        }
        private var stop = false
        func reverseMiddleOrder(_ block: @escaping ((Key, Value), inout Bool) -> Void) {
            stop = false
            right?.reverseMiddleOrder(block)
            block(item, &stop)
            if !stop {
                left?.reverseMiddleOrder(block)
            }
        }
    }
    
    var root: Node? = nil
    
    var count: Int { size(root) }
    
    subscript(key: Key) -> Value? {
        set {
            put(key, newValue)
        }
        get {
            get(key)
        }
    }
    
    private func isRed(_ node: Node?) -> Bool {
        node?.color == .red
    }
    
    private func size(_ node: Node?) -> Int {
        node?.count ?? 0
    }
    
    public var isEmpty: Bool {
        root == nil
    }
    
    public func get(_ key: Key) -> Value? {
        return get(root, key)
    }
    
    private func get(_ node: Node?, _ key: Key) -> Value? {
        var node = node
        while node != nil {
            if key < node!.item.0 {
                node = node?.left
            } else if key > node!.item.0 {
                node = node?.right
            } else {
                return node?.item.1
            }
        }
        return nil
    }
    
    public func contains(_ key: Key) -> Bool {
        get(key) != nil
    }
    
    public func put(_ key: Key, _ value: Value?) {
        if value == nil {
            return
        }
        root = put(root, key, value!)
        root?.color = .black
    }
    
    private func put(_ node: Node?, _ key: Key, _ value: Value) -> Node? {
        guard node != nil else {
            return Node(key: key, value: value)
        }
        var node = node
        if key < node!.item.0 {
            node?.left = put(node?.left, key, value)
        } else if key > node!.item.0 {
            node?.right = put(node?.right, key, value)
        } else {
            node?.item.1 = value
        }
        
        if isRed(node?.right) && !isRed(node?.left) {
            node = node?.rotateLeft()
        }
        if isRed(node?.left) && isRed(node?.left?.left) {
            node = node?.rotateRight()
        }
        if isRed(node?.left) && isRed(node?.right) {
            node?.flipColors()
        }
        
        node?.count = size(node?.left) + size(node?.right) + 1
        return node
    }
    
    func balance(_ node: Node?) -> Node? {
        var node = node
        if isRed(node?.right) {
            node = node?.rotateLeft()
        }
        if isRed(node?.left) && isRed(node?.left?.left) {
            node = node?.rotateRight()
        }
        if isRed(node?.left) && isRed(node?.right) {
            node?.flipColors()
        }
        node?.count = size(node?.left) + size(node?.right) + 1
        return node
    }
    
    enum Color {
        
        case red
        
        case black
        
        mutating func toggle() {
            switch self {
            case .red:
                self = .black
            case .black:
                self = .red
            }
        }
    }
}

class Solution {
    func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] {
        var counter = Dictionary<Int, Int>()
        for item in nums {
            if let value = counter[item] {
                counter[item] = value + 1
            } else {
                counter[item] = 1
            }
        }
        let tree = RedBlackTree<Int, [Int]>()
        for item in counter {
            var items = tree[item.1]
            if items == nil {
                items = [item.0]
            } else {
                items?.append(item.0)
            }
            tree[item.1] = items
        }
        var items = [Int]()
        tree.root?.reverseMiddleOrder { (item, stop)  in
            if items.count < k {
                for element in item.1 {
                    items.append(element)
                    if items.count == k { break }
                }
            } else {
                stop = true
            }
        }
        return items
    }
}

方法三 排序

排序并选取前k元素。该版本的快速排序比系统排序快一些。

extension Int {
    mutating func increasing() -> Int {
        self += 1
        return self
    }
    mutating func decreasing() -> Int {
        self -= 1
        return self
    }
}
extension Array {
    mutating func quickSort(by comparator: @escaping (Element, Element) -> Bool ) {
        quickSort(low: 0, high: count - 1, by: comparator)
    }
    mutating func quickSort(low: Int, high: Int, by comparator: @escaping (Element, Element) -> Bool ) {
        if high <= low { return }
        let j = partition(low: low, high:high, by: comparator)
        quickSort(low: low, high: j - 1, by: comparator)
        quickSort(low: j + 1, high: high, by: comparator)
    }

    mutating func partition(low: Int, high: Int, by comparator: @escaping (Element, Element) -> Bool) -> Int {
        var i = low
        var j = high + 1
        let v = self[low]
        while true {
            while comparator(self[i.increasing()], v) && i != high {}
            while comparator(v, self[j.decreasing()]) && i != low {}
            if i >= j { break }
            swapAt(i, j)
        }
        swapAt(low, j)
        return j
    }
}

class Solution {
    func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] {
        var items = nums.reduce(into: [Int: Int]()) { (counter, item) in
            counter[item] = (counter[item] ?? 0) + 1
        }.map { $0 }
        items.quickSort {
            $0.1 > $1.1
        }
        return items[0..<k].map { $0.0 }
    }
}
上一篇下一篇

猜你喜欢

热点阅读