入栈操作的合法性 【重复元素】

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

* 若序列元素没有重复 

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

假设给定入栈元素: 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();
    }

* 若序列元素存在重复值

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

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

 

posted @ 2018-03-03 12:29  白常福  阅读(421)  评论(0编辑  收藏  举报