您没有说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)))