【问题标题】:How to find out all the popping out possibilities of two stacks?如何找出两个堆栈的所有弹出可能性?
【发布时间】:2012-06-08 04:39:10
【问题描述】:

这里有两个栈:

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 的所有可能性?

非常感谢!

【问题讨论】:

  • 可能性是什么意思?堆栈 A 只能弹出以给出:4、3、2、1 和 B 到 8、7、6、5。你的意思是你正在尝试找到可以弹出 A 和 B 的各种方法,(如 pop(A)、pop(B)、pop(A)、pop(A)、pop(B)..)和这样的?
  • @Amit ,这正是我的意思,很抱歉造成混乱。
  • A和B可以有重复的元素吗?重复是指 A 和 B 中都存在相同的元素....如果是,我们是否必须计算 C 和 D 的唯一组合?
  • @RaviGupta 不,所有商品都是独一无二的。
  • 任何有兴趣的人:cs.stackexchange.com/questions/2257/…

标签: algorithm data-structures stack


【解决方案1】:

我有一个想法,但不知道是否正确:

设置一个有 8 位的堆栈,1 表示 A pop,0 表示 B pop(只要确保有四个 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]);
}

}

【讨论】:

  • 要这样做,您需要创建一个长度为 16 的位数组 - 从 A/B 到 B/C。这是一个昂贵的算法 O(2^(2^n)) 其中 n 是每个堆栈中的元素数
【解决方案2】:

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

但是,会有重复,请考虑每个堆栈上只有两个元素的情况。如果将 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)

不过,我看不出有什么方法可以更有效地生成这些。

【讨论】:

    【解决方案3】:

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

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

    恰好有 8 个选择 4 个这样的序列。所以只需iterate over every such sequence(“无重复组合”) 就能得到你的答案。

    【讨论】:

    • 这并没有告诉你 C 和 D 的可能性
    • @dfb:是的,确实如此。例如,将前四个字母读为“pop(A),push(C);pop(A),push(D);pop(B),push(C);pop(A),push(D)”等
    • ?? - 序列中的第一个字母在哪里表明它应该去 C 而不是 D。我读到了这个问题,因为你可以在每个步骤中选择两者
    • @dfb:哦,我明白了;我们似乎对这个问题的解释不同。我以为他在推 C 和 D 之间交替。我会在上面的 cmets 中问。
    猜你喜欢
    • 2019-08-08
    • 2014-12-18
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 1970-01-01
    • 2018-05-09
    相关资源
    最近更新 更多