进出栈的多样性问题。
1 套碗游戏的取碗顺序问题
问题描述
小F正在玩一个套碗的游戏,每个碗都有一个编号,从1到n,它们从大到小被套在一根木棍上。小F只能从木棍上取最上面的碗,每次只能取一个。现在你需要判断给定的取碗顺序是否可行。如果可行,那么返回1,否则返回0。
例如,对于2个碗,取碗的顺序可以是 2 1 或 1 2,这两种顺序都是合法的。而对于3个碗,给定顺序 3 1 2 不可能通过合法操作实现,因此该顺序不可行。
测试样例
样例1:
输入:
M = 2, a = [1, 2]
输出:1
样例2:
输入:
M = 3, a = [3, 1, 2]
输出:0
样例3:
输入:
M = 4, a = [1, 3, 2, 4]
输出:1
思路
这道题光看题目我是看不懂的,然后琢磨了一下样例,发现其实就是进出栈的多样性的问题。 规定栈一定是从小到大排序。那么1,2,3 三个元素有多种进栈和出栈的可能性,比如1进栈,1出栈,然后23进栈,32出栈,但是不能是3 1 2 的顺序,因为1 2 3依次进栈的话一定是 1进栈,2进栈,3进栈,然后3 2 1出栈。 当3先出栈的时候,21已经在栈里了,这个时候出栈顺序就是2 1而不是1 2.
所以当一个元素出栈时,它之前的元素一定已经全都进栈了。
代码实现
def solution(M: int, a: list) -> int:
# write code here
stack = []
stack_index = 0
for i in a:
if stack:
if stack[-1] == i:
stack.pop()
else:
break
else:
for j in range(stack_index+1, i):
stack.append(j)
stack_index = i
return len(stack) == 0
if __name__ == '__main__':
print(solution(2, [1, 2]) == 1)
print(solution(3, [3, 1, 2]) == 0)
print(solution(4, [1, 3, 2, 4]) == 1)
1 套碗游戏的取碗顺序问题(二)
问题描述
小F正在玩一个套碗的游戏,每个碗都有一个编号,从1到n,它们从大到小被套在一根木棍上。小F只能从木棍上取最上面的碗,每次只能取一个。现在你需要计算总共有多少种取碗的顺序。
例如,对于2个碗,取碗的顺序可以是 2 1 或 1 2,这两种顺序都是合法的。而对于3个碗,给定顺序 3 1 2 不可能通过合法操作实现,因此该顺序不可行。
测试样例
样例1:
输入:
M = 2
输出:2
样例2:
输入:
M = 3
输出:5
样例3:
输入:
M = 4
输出:14
思路
这道题其实就是给定一个顺序的进栈顺序, 1-n,有多少种出栈顺序。 那就是卡特兰数的计算,可以用动态规划来解。
当一个无限大的栈中按照1到n的顺序进栈,合法的出栈序列数量即为第n个卡特兰数。
首次出空之前第一个出栈的序数k将1n的序列分成两个序列,其中一个是1k-1,序列个数为k-1,另外一个是k+1~n,序列个数是n-k。那么根据乘法定理,此时出栈的排列数就是(k-1) * (n-k)
而k的取值可以是1-n,所以给定n,答案就是k取1-n的累和。
这就是卡特兰数的一个递推式子:
这是一个递推的过程,所以可以用动态规划数组来求解。
代码
def solution(M):
dp = [0] * (M+1)
dp[0] = 1
for i in range(1,M+1):
for j in range(1,i+1):
dp[i] += dp[j-1]+ dp[i-j]
# 或者
# for i in range(1, M + 1):
# for j in range(i):
# dp[i] += dp[j] * dp[i - j - 1]
return dp[M]
if __name__ == '__main__':
print(solution(2) == 2)
print(solution(3) == 5)
print(solution(4) == 14)
其他问题
这类题目还可以在扩展,求出栈顺序的全排列。