题1:
给一个数组(1, 2, 2, 3, 4, 5),输出其所有排列,如223415, 425213等,要求一行输出一个排列,并且4不能在位置3(估计从0开始的索引号为是2,我是这样理解的),3和5不能相连。再计算输出的列数为多少?
还算简单,想了想写出来了,回溯的思想。
如下所示:
计算输出列数,用容斥原理解。
首先假设两个2是相异的,求出排列数,设为M,则所求排列数为N = M / 2!
设A = {4在位置3的排列}
B = {3与5相连的排列}
则所求(^表示非,*表示与,+表示或)
M = |^A * ^B|
= I - |A| - |B| + |A * B|
= 6! - 5! - 2*5! + 2 * 3 * 3!
= 396
所以所求N = M / 2 = 198
题2:实现一个栈,push和pop的操作时间复杂度为O(1),并且能够在O(1)的时间内得到栈中元素的最小值。
解:当时没想出来啊,郁闷。
用两个栈实现:栈S1和栈S2,
S1为空时:push时,栈S1和S2中同时存入元素
否则:
push:push进S1,并把push的元素跟S2中栈顶元素比较,如push的元素小则把该元素也push进S2
pop:从S1中pop,如果发现pop的元素与S2栈顶元素相等,则S2也pop
具有下面的循环不变性:
对于S2中的每个元素e:
(1)e位于S2栈顶,则e是S1中所有元素的最小元素
(2)e不位于S2的栈顶,设e1是S2中e的栈位置的上一个元素(靠近出口),则e是S1中e1之下元素序列中的最小元素。
证明:
1)初始化时,显然成立
2)push(e)时,设S2的栈顶元素为e1
2.1)如果e也push进了S2,则e < e1,根据假设e1是S1.push(e)之前S1中的最小元素,因此e是S1.push(e)后S1中的最小元素,(1)成立。对于S1中的元素,e1之上的元素除e外,都大于等于e1,因此e1是S1中e之下的元素序列中的最小元素,S2中e, e1之外的元素性质不变,(2)也成立。
2.2)如果e没有push进S2,则e >= e1,根据假设,显然e1仍然是S1中的最小元素,(1)成立。S2中其他元素性质保持不变,(2)仍然成立。
3)pop时,设S2栈顶为e,e之下的元素为e1(如果存在)
3.1)如果S2也pop了,则根据假设e1是S1中去掉e后的最小元素,(1)成立,其他元素性质不变(2)成立。
3.2)如果S2没有pop,则e仍然是S1中的最小元素,(1)成立,其他元素性质不变(2)成立。
证毕。
伪码如下: