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();
        }

    * 若序列元素存在重复值

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

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

  • 相关阅读:
    ASP.NET Web API 框架研究 Self Host模式下的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式下的消息处理管道
    ASP.NET Web API 框架研究 核心的消息处理管道
    ASP.NET Web API 框架研究 Web Host模式路由及将请求转出到消息处理管道
    ASP.NET Web API 框架研究 ASP.NET Web API 路由
    ASP.NET Web API 框架研究 ASP.NET 路由
    ASP.NET Web API 入门 (API接口、寄宿方式、HttpClient调用)
    MVVM模式
    RESTful Web API 理解
    C# 函数式编程及Monads.net库
  • 原文地址:https://www.cnblogs.com/baichangfu/p/8496317.html
Copyright © 2011-2022 走看看