leetcode 1354 多次求和构造目标数组

232 阅读1分钟
/**
 * @param {number[]} target
 * @return {boolean}
 * 本题没有溢出
 * 1. 每一轮替换后最大的数是替换前整个数组的和,当前数组最大的数就是上一轮被替换的数
 * 2.如果被替换的数被替换前也是最大的数, 那么多次这样的替换过程中多个数组和的差值相等。这个用于加速计算。
 * 3.逆着算, 计算target数组能不能退化成全部由1组成的数组
 */
var isPossible = function(target) {
    if(target.length === 1) return target[0] === 1
    let queue = new PriorityQueue()
    let total = 0
    for(let x of target) {
        total += x
        queue.push(x)
    }
    while(!queue.isEmpty()) {
        let x = queue.peek()
        if(x === 1) break
        // s - (sum - s)
        if((2 * x - total) < 1) return false
        queue.pop()
        let y = queue.peek()
        let k = -1
        let left = total - x
        if(y === 1) {
            k = (x - 1) / left
        } else k = Math.ceil((x - y) / left)
        x -= k * left
        if(x <= 0) return false
        total -= k * left
        queue.push(x)
    }
    return true
};


function PriorityQueue(){
    this.queue = new Array()
}
/**
 * 本优先队列大元素放数组后面,小元素放数组前面
 * splice指定哪个位置就会删除和添加到哪个位置, 所以添加时当前位置
 * 元素后移, 删除时后面元素前移
 */
PriorityQueue.prototype.push = function(x) {
    if(this.queue.length === 0) {
        this.queue.push(x)
        return
    }
    let l = 0
    let r = this.queue.length
    while(l < r) {
        const m = ((l + r) / 2) | 0
        if(this.queue[m]  <= x) {
            l = m + 1
        } else  if(this.queue[m] > x) {
            r = m
        }
    }
    this.queue.splice(l, 0, x)
}

PriorityQueue.prototype.peek = function(){
    return this.queue[this.queue.length - 1]
}
PriorityQueue.prototype.pop = function(){
    return this.queue.pop()
}
PriorityQueue.prototype.isEmpty = function(){
    return this.queue.length === 0
}