zoukankan      html  css  js  c++  java
  • 入栈操作的合法性 【重复元素】

    问题描述:给定两个序列,判断是否为对应合法的入栈出栈序列?

    * 若序列元素没有重复 

    我想到大概三种方式【为简化思路,假设需判定的数组仅仅只有序列是否合法问题,其他的不考虑】

    假设给定入栈元素: 1,3,4,7,2,8

    对应序列: 0,1,2,3,4,5

    那么出栈元素的组合可以是: 1,3,4,7,2,8; ,1,4,2,7,8,3; 4,3,2,8,7,1 ...

    出栈元素对应的序列组合分别是:0,1,2,3,4,5; 0,2,4,3,5,1; 2,1,4,5,3,0 ...

    通过分析入栈和出栈的操作,不难发现出栈的序列可以跳跃增大,却必须依次有序减小(不一定连续)。因此问题转化为判定序列减小必须有序即可,衍生出方法一二。两者的前置操作均为先将元素与序列对应起来,java中放入map即可,map.put(元素 , 入栈序列) 后续判断序列是否合理即可

    方法一:只看出栈和入栈的序列关系,那么出栈是的序列必定是有规律的,具体的关系是:对于任意序列编号,其右边比当前序列编号小的序列组合必定是降序。

    boolean isValid(Object[] seqIn, Object[] seqOut) {
            Map<Object, Integer> map = new HashMap<>();
            int seq = 0, len = seqIn.length;
            //记录元素对应的序列
            for (Object obj : seqIn) {
                map.put(obj, seq++);
            }
            //判断每一个序列右边比其小的都是降序排列
            for (int i = 0; i < len; i++) {
                seq = map.get(seqOut[i]);
                for (int j = i + 1; j < len; j++) {
                    if (map.get(seqOut[j]) < map.get(seqOut[i])) {
                        if (map.get(seqOut[j]) < seq) {
                            seq = map.get(seqOut[j]);
                        } else {
                            return false;
                        }
                    }
                }
            }
            return true;
        }

     方法二:还是利用上述关系,加入动态规划思想,利用一个一维数组记录状态,复杂度降为O(n),思路是:每进行一个合理的出栈操作就将对应状态复制为true,判断是否合理的条件是  当前序列<上一个序列 && 当前序列+1状态为true 不满足则直接结束。

    boolean isValid(Object[] seqIn, Object[] seqOut) {
            Map<Object, Integer> map = new HashMap<>();
            int seq = 0, len = seqIn.length;
            //记录元素对应的序列
            for (Object obj : seqIn) {
                map.put(obj, seq++);
            }
            //初始化状态记录数组
            boolean[] valid = new boolean[len];
            valid[map.get(seqOut[0])] = true;
            for (int i = 1; i < len; i++) {
                if (map.get(seqOut[i]) < map.get(seqOut[i - 1]) && !valid[map.get(seqOut[i]) + 1]) {
                    return false;
                }
                valid[map.get(seqOut[i])] = true;
            }
            return true;
        }

    除了上述两种思路,还可以直接模拟入栈和出栈的过程,若入栈的栈顶元素和给定序列seqOut当前元素相同,则seqOut序列+1,不同则继续入栈。栈为空且seqOut序列最大代表合法,其余情况不合法。

    boolean isValid(Object[] seqIn, Object[] seqOut) {
            int out = 0, len = seqOut.length;
            Stack<Object> stack = new Stack<>();
            //全部入栈后结束操作
            for (int i = 0; i < len; i++) {
                stack.push(seqIn[i]);
                //栈顶元素和待判断序列当前值相同时出栈移位
                while (!stack.empty() && stack.peek().equals(seqOut[out])) {
                    stack.pop();
                    out++;
                }
            }
            return stack.empty();
        }

    * 若序列元素存在重复值

    当元素存在重复时,对于相同元素,总是从最近的那一个开始判断,使得序列出错,上述三种方法均失效。

    但思路都是没有问题的,只需要解决 “总是从最近的那一个开始判断”即可,因此可以改动上述三种方法,做成递归式的,记录下元素出现的个数,遇到相同元素时,贪心迭代所有情况,取结果集的或运算集做为答案。

  • 相关阅读:
    2.2 Scala基础知识
    Linux---用户及权限管理类命令
    Linux---进程控制类命令
    Linux---vim编辑文本文件
    Linux---文件压缩与解压缩命令
    Linux---查找命令
    Linux---基本目录与文件命令
    nginx配置技巧汇总
    Go 内嵌静态资源
    go语言的time.Sleep
  • 原文地址:https://www.cnblogs.com/baichangfu/p/8496317.html
Copyright © 2011-2022 走看看