[LeetCode每日一题] 5731. Seat Reservation Manager

94 阅读1分钟

解法一:二分法。维护一个有序数组,这样在查找和删除的时候时间复杂度都为O(logn)O(logn),空间复杂度O(n)O(n)

class SeatManager {
    arr: number[]
    constructor(n: number) {
        this.arr = [0]
    }

    reserve(): number {
        // 找到第一个arr[idx]!=idx的并插入
        if (this.arr.length == 1) {
            this.arr.push(1)
            return 1
        } else {
            let l = 1, r = this.arr.length-1
            while (l!=r) {
                let m = (l+r)>>1
                if (this.arr[m]==m) l = m+1
                else r = m
            }
            if (l<this.arr.length&&l==this.arr[l]) {
                this.arr.push(l+1)
                return l+1
            }
            this.arr.splice(l, 0, l)
            return l
        }
        
    }

    unreserve(seatNumber: number): void {
        if (this.arr.length == 0) return
        let l = 0, r = this.arr.length-1
        while (l!=r) {
            let m = (l+r)>>1
            if (this.arr[m]==seatNumber) {
                this.arr.splice(m, 1)
                return
            } else if (this.arr[m]>seatNumber) r = m
            else l = m+1
        }
        if (l>=0&&l<this.arr.length&&this.arr[l]==seatNumber) {
            this.arr.splice(l,1)
        }
    }
}

解法二:维护一个小根堆。js没有提供相应的库,只能手写。维护一棵可用数堆,堆本质是一棵完全二叉树,因此我们使用数组保存。父子结点的关系为left_idx=parent_idx*2+1,right_idx=parent_idx*2+2。每次reserve时选择堆的根节点,然后将最后一个数放到前面重新向下调整;unreserve时把该数加入数组最后,然后向上调整,向上调整到上不去了再向下调整。最后构造函数时间复杂度O(n)O(n);reserve函数时间复杂度O(logn)O(logn);unreserve函数时间复杂度O(logn)O(logn)。以上算法的前提是输入都是有效的。

class SeatManager {
    heap: number[]
    constructor(n: number) {
        this.heap = []
        for (let i = 1; i <= n; i++) this.heap.push(i)
    }

    reserve(): number {
        if (this.heap.length==1) return this.heap.pop()
        const res = this.heap[0]
        this.heap[0] = this.heap.pop()
        let idx = 0
        // 往下调整
        const inf = Number.MAX_SAFE_INTEGER
        while (idx<this.heap.length) {
            let idx_l = idx*2+1, idx_r = idx*2+2
            let left = inf, right = inf
            if (idx_l<this.heap.length) left = this.heap[idx_l]
            if (idx_r<this.heap.length) right = this.heap[idx_r]
            if (left<right&&left<this.heap[idx]) {
                [this.heap[idx],this.heap[idx_l]] = [this.heap[idx_l],this.heap[idx]]
                idx = idx_l
            }
            else if (right<left&&right<this.heap[idx]) {
                [this.heap[idx],this.heap[idx_r]] = [this.heap[idx_r],this.heap[idx]]
                idx = idx_r
            } else break
        }
        return res
    }

    unreserve(seatNumber: number): void {
        this.heap.push(seatNumber)
        // 向上调整
        let idx = this.heap.length-1
        while (idx>0) {
            if (this.heap[Math.floor((idx-1)/2)]>this.heap[idx]) {
                [this.heap[Math.floor((idx-1)/2)],this.heap[idx]] = [this.heap[idx],this.heap[Math.floor((idx-1)/2)]]
                idx = Math.floor((idx-1)/2)
            } else break
        }
        // 向下调整
        const inf = Number.MAX_SAFE_INTEGER
        while (idx<this.heap.length) {
            let idx_l = idx*2+1, idx_r = idx*2+2
            let left = inf, right = inf
            if (idx_l<this.heap.length) left = this.heap[idx_l]
            if (idx_r<this.heap.length) right = this.heap[idx_r]
            if (left<right&&left<this.heap[idx]) {
                [this.heap[idx],this.heap[idx_l]] = [this.heap[idx_l],this.heap[idx]]
                idx = idx_l
            }
            else if (right<left&&right<this.heap[idx]) {
                [this.heap[idx],this.heap[idx_r]] = [this.heap[idx_r],this.heap[idx]]
                idx = idx_r
            } else break
        }
    }
}