算法学习记录(十七)

176 阅读1分钟

问:

  1. 不停的往一个数组里加数字,如何随时拿到它的中位数
  2. 打印一个字符串全部子集,包括空字符串

解:

  1. 创建一个大根堆和小根堆,先往大根堆放一个数,下次再放的数如果比大根堆根节点大就放入小根堆,反之放入大根堆。当两个堆大小相差达到2的时候,就匀一个到少的堆里。这样两个堆的根节点就与中位数有关。
class MedianFinder {
    public bigHeap: number[]
    public smallHeap: number[]
    constructor() {
        this.bigHeap = []
        this.smallHeap = []
    }

    addNum(num: number): void {
        if (!this.bigHeap.length || num < this.bigHeap[0]) {
            this.heapInset(num, this.bigHeap, true)
            if (this.bigHeap.length - this.smallHeap.length > 1) {
                [this.bigHeap[this.bigHeap.length - 1], this.bigHeap[0]] = [this.bigHeap[0], this.bigHeap[this.bigHeap.length - 1]]
                this.heapInset(this.bigHeap.pop(), this.smallHeap, false)
                this.heapFy(0, this.bigHeap, true)
            }
        } else {
            this.heapInset(num, this.smallHeap, false)
            if (this.smallHeap.length - this.bigHeap.length > 1) {
                [this.smallHeap[this.smallHeap.length - 1], this.smallHeap[0]] = [this.smallHeap[0], this.smallHeap[this.smallHeap.length - 1]]
                this.heapInset(this.smallHeap.pop(), this.bigHeap, true)
                this.heapFy(0, this.smallHeap, false)
            }
        }
    }

    findMedian(): number {
        if (this.bigHeap.length === this.smallHeap.length) return (this.bigHeap[0] + this.smallHeap[0]) / 2
        if (this.bigHeap.length > this.smallHeap.length) return this.bigHeap[0]
        return this.smallHeap[0]
    }
    heapInset(num: number, heap: number[], type: boolean) : void {
        heap.push(num)
        let curIdx = heap.length - 1
        while(type ? (heap[curIdx] > heap[Math.floor((curIdx - 1) / 2)]) : heap[curIdx] < heap[Math.floor((curIdx - 1) / 2)]) {
            [heap[curIdx], heap[Math.floor((curIdx - 1) / 2)]] = [heap[Math.floor((curIdx - 1) / 2)], heap[curIdx]];
            curIdx = Math.floor((curIdx - 1) / 2)
        }
    }
    heapFy(idx: number, heap: number[], type: boolean) : void {
        let leftIdx = 2 * idx + 1
        let rightIdx = leftIdx + 1
        // 最终下标
        let resIdx = idx
        // 左不越界,并且比最终下标大,就取左
        if (leftIdx < heap.length && (type ? heap[leftIdx] > heap[resIdx] : heap[leftIdx] < heap[resIdx])) resIdx = leftIdx
        // 右不越界,并且比最终下标大,就取右
        if (rightIdx < heap.length && (type ? heap[rightIdx] > heap[resIdx] : heap[rightIdx] < heap[resIdx])) resIdx = rightIdx;
        if (resIdx !== idx) {
            [heap[idx], heap[resIdx]] = [heap[resIdx], heap[idx]]
            this.heapFy(resIdx, heap, type)
        }
    }
}
  1. 声明临时变量tempStr用于保存一次递归完成时最终结果。如果递归到了最后一位,就把这个结果放入结果数组。从0开始递归这个字符串,如果选择要当前字符str[cur],tempStr += str[cur],然后递归下一位。如果选择不要,就把这个字符删掉,继续递归下一位。
function getAllSubset(str) {
    let res = []
    let tempStr = ''
    function getRes(str, idx) {
        if (idx === str.length) {
            res.push(tempStr)
            return
        }
        // 如果加这个字符
        tempStr += str[idx]
        getRes(str, idx + 1)
        // 如果不加这个字符
        tempStr = tempStr.slice(0, -1)
        getRes(str, idx + 1)
    }
    getRes(str, 0)
    return res
}