跟着代码随想录练算法——队列和栈(js)

232. 用栈实现队列

一个栈用做输入栈,一个作为输出栈

  • push 直接push在输入栈 inStack的末尾
  • pop 先判断输出栈是否有元素,如果没有,需要将输入栈的元素一个个pop出来再push进输出栈,最后将输出栈pop并且返回
  • peek 前面与pop一样,最终不需要pop输出栈的元素,只需要将该元素返回即可
  • empty 判断两个栈,如果都为空才返回 true,否则返回false
var MyQueue = function() {
    this.inStack = []
    this.outStack = []
};

/** 
 * @param {number} x
 * @return {void}
 */
MyQueue.prototype.push = function(x) {
    this.inStack.push(x)
    console.log('push',this.inStack,this.outStack)
};

/**
 * @return {number}
 */
MyQueue.prototype.pop = function() {
    //outStack 不为空
    if(this.outStack.length === 0){
        while(this.inStack.length){
            this.outStack[this.outStack.length] = this.inStack.pop()
            
        }
           
    }
    console.log('pop',this.inStack,this.outStack)
    return this.outStack.pop()  
};

/**
 * @return {number}
 */
MyQueue.prototype.peek = function() {
    if(this.outStack.length === 0){
        while(this.inStack.length){
            this.outStack[this.outStack.length] = this.inStack.pop()
            
        }
          
    }
    console.log('peek',this.inStack,this.outStack)
    return this.outStack[this.outStack.length - 1]  
};

/**
 * @return {boolean}
 */
MyQueue.prototype.empty = function() {
    if(this.outStack.length === 0 && this.inStack.length === 0){
        return true
    }
    console.log('empty',this.inStack,this.outStack)
    return false
};

225. 用队列实现栈

一个队列用来放元素,一个用来临时保存

  • push 直接push进队列1的末尾
  • pop,top 先将队列1中的 this.queue1.length - 1 个元素放在queue2中,队列是先进先出,不会改变元素顺序,相当于直接复制过去,然后在将queue1中剩余的元素保存下来,再pop出去(top的话就不需要pop),再将queue2中的元素再复制到1里去,将刚刚保存的元素作为返回值,如果是top操作还需要把这个元素放回queue1
  • empty 直接判断queue1是否为空
var MyStack = function() {
    this.queue1 = []
    this.queue2 = []
};

/** 
 * @param {number} x
 * @return {void}
 */
MyStack.prototype.push = function(x) {
    this.queue1.push(x)
};

/**
 * @return {number}
 */
MyStack.prototype.pop = function() {
    while(this.queue1.length - 1){
        this.queue2.push(this.queue1.shift())
    }
    let item = this.queue1.pop()
    while(this.queue2.length){
        this.queue1.push(this.queue2.shift())
    }
    return item
};

/**
 * @return {number}
 */
MyStack.prototype.top = function() {
    while(this.queue1.length - 1){
        this.queue2.push(this.queue1.shift())
    }
    let item = this.queue1.pop()
    while(this.queue2.length){
        this.queue1.push(this.queue2.shift())
    }
    this.queue1.push(item)
    return item
};

/**
 * @return {boolean}
 */
MyStack.prototype.empty = function() {
    if(this.queue1.length === 0) return true
    return false
};

1047. 删除字符串中的所有相邻重复项

/**
 * @param {string} s
 * @return {string}
 */
var removeDuplicates = function(s) {
    if(!s || s.length === 0) return true
    let stack = []
    let arr = s.split('')
    for(let i = 0; i < arr.length; i++){
        if(stack.length === 0 || arr[i] !== stack[stack.length - 1]){
            stack.push(arr[i])
        }else{
            stack.pop()
        }
    }
    return stack.join('')
};

20. 有效的括号

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    let obj = {
        '{':'}',
        '(':')',
        '[':']'
    }
    let arr = s.split('')
    let stack = []
    for(let i = 0; i < arr.length; i++){
        if(obj[arr[i]]){
            stack.push(arr[i])
        }else{
            if(stack.length === 0) return false
            let top = stack.pop()
            if(obj[top] !== arr[i]) return false
        }
    }
    if(stack.length !== 0) return false
    return true
};

239. 滑动窗口最大值

维护一个单调递减的队列,队列的头表示当前区间的最大元素

  • 指针ij指向窗口的头和尾
  • 每次移动窗口需要取更新这个单调队列
    • 如果从窗口中踢出去的元素nums[i-1]和队列的头部相等,则需要将队头元素出队,使用shift方法
    • 然后还需要将新加入的窗口元素nums[j]与队列尾部元素比较,如果队尾元素比nums[j]要小则pop出去,直到队列为空或者队列最后一个元素大于等于nums[j],保证更新后队列依旧是单调的
  • 更新完队列后,队列头元素也就是当前窗口最大值,放到ans中
  • 最后j走到nums的最后一个元素,遍历结束,返回ans
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var maxSlidingWindow = function(nums, k) {
    let queue = [nums[0]]
    if(nums.length === 1) return queue
    for(let i = 1; i < k; i++){
        while(queue.length && nums[i] > queue[queue.length - 1]){
            queue.pop()
        }
        queue.push(nums[i])
    }
    let ans = [queue[0]]
    let i = 1
    let j = k
    while(j < nums.length){
        if(nums[i-1] === queue[0]){
            queue.shift()
        }
        while(queue.length && nums[j] > queue[queue.length - 1]){
            queue.pop()
        }
        queue.push(nums[j])
        ans.push(queue[0])
        i ++
        j ++
    }
    return ans
};

150. 逆波兰表达式求值

  • 遇到字符串就从栈中取出两个数做计算
  • 注意除法运算,栈顶元素是除数,下面的那一个是被除数。并且除法是保留整数部分,也就是正数是向下取整,负数是向上取整
  • 遇到数组就先将字符串转换为数字再放入栈中
/**
 * @param {string[]} tokens
 * @return {number}
 */
var evalRPN = function(tokens) {
    let stack = []
    for(let i = 0; i < tokens.length; i++){
        if(tokens[i] === '+' || tokens[i] === '-' || tokens[i] === '*' || tokens[i] === '/'){
            let a = stack.pop()
            let b = stack.pop()
            switch(tokens[i]){
                case '+':
                    stack.push(b + a)
                    break
                case '-':
                    stack.push(b - a)
                    break
                case '*':
                    stack.push(b * a)
                    break
                case '/':
                    if(b/a > 0)
                        stack.push(Math.floor(b/a))
                    else stack.push(Math.ceil(b/a))
                    break
            }
        }else{
            stack.push(Number(tokens[i]))
        }
    }
    return stack[0]
};

347. 前 K 个高频元素

思路:

  • 使用map统计数字出现的频率,作为该元素的权值
  • 遍历map中的元素,将key放入arr数组,维护一个大小为k的小顶堆:
    • 当放元素进arr时发现小顶堆大小已经等于k,判断当前元素频率和堆顶元素评论,若比堆顶元素频率还要小则忽略,若大于堆顶元素频率,则现将堆尾元素弹出并且替代堆顶,然后向下调整,最后再放入当前元素,向上调整
    • 如果最小堆还没有达到k,则只需要将元素放入,然后向上调整
    • 如果最小堆内没有元素,则只需要将元素放入,不需要调整
  • 有一个注意点就是当k=1 时,上一步的放入元素的第一小点,只需要弹出元素就可以了。
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */

var topKFrequent = function(nums, k) {
    let map = new Map()
    for(let i = 0; i < nums.length; i++){
        if(map.has(nums[i])){
            map.set(nums[i], map.get(nums[i]) + 1)
        }else {
            map.set(nums[i], 1)
        }
    }
    let arr = []
    let size = 0
    function dubbleUp(index){
        while(index){
            let parentIndex = Math.floor((index - 1)/2)
            if(map.get(arr[parentIndex]) > map.get(arr[index])){
                [arr[parentIndex], arr[index]] = [arr[index], arr[parentIndex]]
                index = parentIndex
            }else{
                break
            }
        }
    }
    function dubbleDown(index){
        const lastIndex = arr.length - 1
        while(index < lastIndex){
            let findIndex = index
            let leftIndex = index*2 + 1            
            let rightIndex = index*2 + 2
            if(leftIndex <= lastIndex && map.get(arr[leftIndex]) < map.get(arr[findIndex])){
                findIndex = leftIndex
            }
            if(rightIndex <= lastIndex && map.get(arr[rightIndex]) < map.get(arr[findIndex])){
                findIndex = rightIndex
            }
            if(findIndex > index){
                [arr[findIndex], arr[index]] = [arr[index], arr[findIndex]]
                index = findIndex
            }else{
                break
            }
        }
    }
    map.forEach((val, key) => {
        // console.log('val, key,size, arr:',val, key, size, arr)
        if(size >= k){
            // 如果当前元素比堆顶元素权值要大
            if(map.get(key) > map.get(arr[0])){
                if(k > 1){
                    arr[0] = arr.pop()
                    dubbleDown(0)
                }else arr.pop()
                
                arr.push(key)
                dubbleUp(size - 1)
            }
        }else if(size === 0){
            arr.push(key)
            size ++
        }else {
            arr.push(key)
            size ++
            dubbleUp(size - 1)
        }
    })
    return arr
    
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值