JS实现判断栈的压入、弹出序列

作为前端,接触算法的机会可能比较少,但是我们脑子可不能锈了~

一道题目:输入两个整数序列,第一个序列表示栈的压入顺序,判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。
例如:1,2,3,4,5是某个栈的压入顺序,序列4,5,3,2,1是该栈对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

这里,我用JS来实现这道题,其中用数组来模拟栈的操作。主要思路就是:

  1. 在判断第一个弹出的数字时,如果刚好是入栈的栈顶元素,那么直接弹出。继续从第1步开始判断下一个弹出的数字。
  2. 如果不是,则将入栈序列中不为弹出数字的数字压入到辅助栈中直到找到这个弹出元素(若没找到,则直接可以退出,说明弹出序列不可能)。
  3. 如果弹出序列存在的话,那么接下来的弹出元素只有两个可能:①出现在入栈的栈顶;②存在于辅助栈中。然后循环判断这两种状况直到弹出栈变为空即可。
  4. 如果以上两种情况都没匹配到,那么该弹出序列就不可能了。

代码如下,有详细的注释:

/**
 * 这里使用JS实现,用数组来模拟栈的操作
 * @param {栈输入的顺序(数组表示)} pushOrder 
 * @param {栈输出的顺序(数组表示)} popOrder 
 */


function isPopPossible(pushOrder, popOrder) {
    var isPossible = false
    /** 1. 确认输入的合法性 */
    if (pushOrder != null && popOrder != null && Array.isArray(pushOrder) && Array.isArray(popOrder)) {
        /** 2. 都为空直接返回true(这里认为两个栈都是空的话,就是true) */
        if (pushOrder.length === 0 && popOrder.length === 0) {
            return true
        }
        /** 3. 保证两个输入的序列长度是相等的  */
        if (pushOrder.length === popOrder.length) {
            /** JS中数组传入的是引用,为了保证不改变原数组,这里创建一份他们的副本 */
            var pushOrder_copy = [...pushOrder]
            var popOrder_copy = [...popOrder]
            /** 这个数组作为辅助的栈 */
            var helpStack = []
            /** 获取第一个弹出的元素(此时弹出序列减少了一个元素) */
            var now = popOrder_copy.shift()
            /** 将栈顶不为第一个弹出的元素的元素压入辅助栈 */
            while (pushOrder_copy.length > 0 && pushOrder_copy[pushOrder_copy.length - 1] !== now) {
                helpStack.unshift(pushOrder_copy.pop())
            }
            /** 若所有元素都弹出了还没找到和第一个弹出元素相等的元素,则直接返回false */
            if (pushOrder_copy.length === 0) {
                return false
            }
            /** 说明找到了,则将匹配到的这个元素弹出 */
            pushOrder_copy.pop()
            /** 4. 遍历剩下的弹出栈元素(这里入栈序列可能不为空,辅助栈可能不为空,弹出栈可能不为空) */
            while (popOrder_copy.length > 0) {
                /** 获取下一个弹出元素 */
                now = popOrder_copy.shift()
                /** 如果入栈序列的栈顶为该弹出元素,则将其从入栈中弹出 */
                if (pushOrder_copy.length > 0 && pushOrder_copy[pushOrder_copy.length - 1] === now) {
                    pushOrder_copy.pop()
                } else {
                    /** 遍历辅助栈,看弹出的元素是否在辅助栈中 */
                    while (helpStack.length > 0) {
                        /** 如果辅助栈栈顶的元素不为弹出的元素,则将其压入到入栈中 */
                        if (helpStack[0] !== now) {
                            pushOrder_copy.push(helpStack.shift())
                        } else {
                            /** 辅助栈中找到了该弹出元素,则将该元素弹出,跳出循环,进行下一轮弹出元素的判断 */
                            helpStack.shift()
                            break
                        }
                    }
                }
            }
            /** 最终入栈和出栈都为空,说明都匹配到了,则是可能的弹出序列 */
            if(popOrder_copy.length === 0 && pushOrder_copy.length === 0) {
                isPossible = true
            }
        }
    }
    return isPossible
}


/** =====测试用例===== */
/** 1.两个都为空 */
console.log(isPopPossible([], [])) //true,
/** 2.其中一个不存在 */
console.log(isPopPossible(null, [])) //false
/** 3.元素个数不匹配 */
console.log(isPopPossible([1, 2, 3, 4], [1, 2, 3])) //false
/** 4.元素不匹配 */
console.log(isPopPossible([1, 2, 3, 4], [1, 2, 3, 5])) //false,
/** 5.比较常规的测试 */
console.log(isPopPossible([1, 2, 3, 4, 5], [4, 5, 3, 2, 1])) //true
/** 5.不匹配 */
console.log(isPopPossible([1, 2, 3, 4, 5], [4, 5, 3, 1, 2])) //false
/** 6.入栈的序列为空,都在辅助栈中 */
console.log(isPopPossible([1, 2, 3, 4, 5], [5, 4, 3, 2, 1])) //true,
/** 7. 输入栈和辅助栈来回交替 */
console.log(isPopPossible([1, 3, 2, 0], [1, 2, 0, 3])) //true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码飞_CC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值