【问题标题】:Stack permutations sorted in lexicographical order按字典顺序排序的堆栈排列
【发布时间】:2020-09-17 16:03:23
【问题描述】:

数字 N 的堆栈排列定义为您可以通过执行以下操作打印的序列数

  1. 保留两堆,说 A 和 B。
  2. 在 B 中以相反的顺序将数字从 1 推到 N。(因此 B 的顶部是 1,B 中的最后一个元素是 N)
  3. 执行以下操作
  • 从 A 或 B 中选择顶部元素并将其打印并删除(弹出)。这只能在非空堆栈上完成。

  • 将顶部元素从 B 移动到 A(如果 B 非空)

  • 如果两个堆栈都是空的,则停止

通过按某种顺序执行这些操作获得的所有可能序列称为stack permutations

例如:N = 2
堆栈排列是 (1, 2) 和 (2, 1)
例如:N = 3
堆栈排列是 (1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1) 和 (3, 2, 1)

N 个数字的堆栈排列数是 C(N),其中 C(N) 是第 N 个Catalan Number

假设我们为给定的 N 生成所有堆栈排列,然后按字典顺序(字典顺序)打印它们,我们如何确定第 k 个排列,而不实际生成所有排列然后对它们进行排序?

我想要一些可编程的算法方法。

【问题讨论】:

    标签: algorithm math stack permutation


    【解决方案1】:

    您没有说k 应该是基于0 还是基于1。我选择了 0。切换回来很容易。

    方法是首先编写一个函数来计算从给定的决策点有多少堆栈排列。使用 memoization 使其快速。然后通过跳过导致字典顺序较小的排列的决策继续向下决策树。这将导致您想要的决策列表。

    def count_stack_permutations (on_b, on_a=0, can_take_from_a=True, cache={}):
        key = (on_b, on_a, can_take_from_a)
        if on_a < 0:
            return 0 # can't go negative.
        elif on_b == 0:
            if can_take_from_a:
                return 1 # Just drain a
            else:
                return 0 # Got nothing.
        elif key not in cache:
            # Drain b
            answer = count_stack_permutations(on_b-1, on_a, True)
            # Drain a?
            if can_take_from_a:
                answer = answer + count_stack_permutations(on_b, on_a-1, True)
            # Move from b to a.
            answer = answer + count_stack_permutations(on_b-1, on_a+1, False)
            cache[key] = answer
    
        return cache[key]
    
    def find_kth_permutation (n, k):
        # The end of the array is the top
        a = []
        b = list(range(n, 0, -1))
        can_take_from_a = True # We obviously won't first. :-)
    
        answer = []
        while 0 < max(len(a), len(b)):
            action = None
            on_a = len(a)
            on_b = len(b)
    
            # If I can take from a, that is always smallest.
            if can_take_from_a:
                if count_stack_permutations(on_b, on_a - 1, True) <= k:
                    k = k - count_stack_permutations(on_b, on_a - 1, True)
                else:
                    action = 'a'
            # Taking from b is smaller than digging into b so I can take deeper.
            if action is None:
                if count_stack_permutations(on_b-1, on_a, True) <= k:
                    k = k - count_stack_permutations(on_b-1, on_a, True)
                else:
                    action = 'b'
            # Otherwise I will move.
            if action is None:
                if count_stack_permutations(on_b-1, on_a, False) < k:
                    return None # Should never happen
                else:
                    action = 'm'
    
            if action == 'a':
                answer.append(a.pop())
                can_take_from_a = True
            elif action == 'b':
                answer.append(b.pop())
                can_take_from_a = True
            else:
                a.append(b.pop())
                can_take_from_a = False
        return answer
    
    # And demonstrate it in action.
    for k in range(0, 6):
        print((k, find_kth_permutation(3, k)))
    

    【讨论】:

    • 可以将unrank函数发布到吗?
    • @TThoEinthausend 我必须写它。但这将是一个弄清楚接下来会做出哪个决定的问题,然后计算你跳过了多少。
    【解决方案2】:

    这可以使用 factoradic(https://en.wikipedia.org/wiki/Factorial_number_system)

    如果您需要 Java 中的快速解决方案,请使用 JNumberTools

    JNumberTools.permutationsOf("A","B","C")
                    .uniqueNth(4) //next 4th permutation
                    .forEach(System.out::println);
    

    此 API 将直接按字典顺序生成下一个第 n 个排列。因此,您甚至可以生成 100 个项目的下十亿个排列。

    用于生成给定大小的下一个排列:

    JNumberTools.permutationsOf("A","B","C")
                    .kNth(2,4) //next 4th permutation of size 2
                    .forEach(System.out::println);
    

    JNumberTools 的 maven 依赖是:

    <dependency>
        <groupId>io.github.deepeshpatel</groupId>
        <artifactId>jnumbertools</artifactId>
        <version>1.0.0</version>
    </dependency>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-25
      • 1970-01-01
      相关资源
      最近更新 更多