如何找出两个堆栈的所有弹出的可能性?

时间:2012-06-04 02:23:17

标签: algorithm data-structures stack

这里有两个堆栈:

A: 1,2,3,4 <- Stack Top
B: 5,6,7,8

A和B将弹出到其他两个堆栈:C和D.

Example: 
 pop(A),push(C),pop(B),push(D).
 If an item have been popped out , it must be pushed to C or D immediately.

那么,是否有算法可以找出C和D的所有可能性?

非常感谢!

3 个答案:

答案 0 :(得分:0)

您可以生成堆栈中所有可能的弹出窗口的列表,然后模拟:

但是,当每个堆栈上只有两个元素时,会考虑重复。如果a被推到c,而b被推到d,那么推送它们的顺序并不重要。

def simulate(steps):
    source={'a':range(4),'b':range(4,8)}
    res = {'c':"",'d':""}; 
    for i,step in enumerate(steps):
        res[step[1]]+=str(source[step[0]].pop())
    # this is what each stack will look like
    return res['c']+'-'+res['d']  

def steps(a_left,b_left):
    ret = []
    if a_left>0:
        substeps = steps(a_left-1,b_left)
        ret.extend( [ x + [('a','c')] for x in substeps] )
        ret.extend( [ x + [('a','d')] for x in substeps] )
    if b_left>0:
        substeps = steps(a_left,b_left-1)
        ret.extend(  [ x + [('b','c')] for x in substeps] )
        ret.extend(  [ x + [('b','d')] for x in substeps] )
    if(len(ret)==0):
        return [[]]
    return ret;

结果:

>>> [x for x in steps(1,1)]
[[('b', 'c'), ('a', 'c')], [('b', 'd'), ('a', 'c')], [('b', 'c'), ('a', 'd')], [
('b', 'd'), ('a', 'd')], [('a', 'c'), ('b', 'c')], [('a', 'd'), ('b', 'c')], [('
a', 'c'), ('b', 'd')], [('a', 'd'), ('b', 'd')]]
>>> [simulate(x) for x in steps(1,1)]
['73-', '3-7', '7-3', '-73', '37-', '7-3', '3-7', '-37']
>>> len(set([simulate(x) for x in steps(4,4)]))
5136  

如果我们考虑只有一个目标堆栈的两个堆栈,我们可以在(2 * n)!/(n!)^ 2找到唯一堆栈的数量。这与8个元素的排列数相同,其中4个是'A',其中4个是'B'。然后我们可以通过将它们分成子集来将它们分配给每个单独的堆栈 - 每个堆栈具有N个唯一数字的子集的数量将是2 ^(2 ^ n)

(2^(2*n))/((2*n)!/(n!)^2)
但是,我没有看到更有效地生成这些内容的方法。

答案 1 :(得分:0)

我有个主意,但不知道这是否正确:

设置一个有8位的堆栈,1表示一个弹出,0表示B弹出(只要确保有四个1和四个0)。

所以答案就是找出8位数组合的所有可能性。

然后迭代8位以弹出A或B.

以下是代码:

public class Test {
public static void generate(int l, int[] a) {
    if (l == 8) {
        if (isValid(a)) {
            for (int i = 0; i < l; i++) {
                System.out.print(a[i]);
            }
            System.out.println();
        }
    } else {
        for (int i = 0; i < 2; i++) {
            a[l] = i;
            generate(++l, a);
            --l;
        }
    }
}

// the combination must have four 0 and four 1.
public static boolean isValid(int[] a) {
    int count = 0;
    for (int i = 0; i < a.length; i++) {
        if (a[i] == 0) count++;
    }
    if (count != 4) return false;
    return true;
}

public static void main(String[] args) {
    generate(0, new int[8]);
}

}

答案 2 :(得分:0)

C和D的内容可以按任意顺序写成四个A和四个B的序列。

  

AABABBBA (表示弹出A两次,然后B弹一次,然后A弹一次等)

确实有 8选择4 这样的序列。所以只需iterate over every such sequence (“不重复的组合”)即可获得答案。