入栈操作的合法性 【重复元素】
问题描述:给定两个序列,判断是否为对应合法的入栈出栈序列?
* 若序列元素没有重复
我想到大概三种方式【为简化思路,假设需判定的数组仅仅只有序列是否合法问题,其他的不考虑】
假设给定入栈元素: 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(); }
* 若序列元素存在重复值
当元素存在重复时,对于相同元素,总是从最近的那一个开始判断,使得序列出错,上述三种方法均失效。
但思路都是没有问题的,只需要解决 “总是从最近的那一个开始判断”即可,因此可以改动上述三种方法,做成递归式的,记录下元素出现的个数,遇到相同元素时,贪心迭代所有情况,取结果集的或运算集做为答案。