[程序源代码面试指南第二版] 用栈来实现汉诺塔问题
描述
汉诺塔(非递归)
需求
不能直接从左到右或者从右到左,必须经过中间
咳咳
主要两个原则:
- 不能违反小压大原则 -from栈弹出的num压入to栈中,num必须小于当前to栈的栈顶
- 相邻不可逆原则 2.1. 上一步是L->M 根据小压大原则,L->M动作不会重复发生 根据相邻不可逆原则,M->L动作不会发生 根据小压大原则,R->M,M->R只有一个会达标
2.2. 上一步是M->L 根据小压大原则,M->L动作不会重复发生 根据相邻不可逆原则,L->M动作不会发生 根据小压大原则,R->M,M->R只有一个会达标
2.3. 上一步是R->M 根据小压大原则,R->M动作不会重复发生 根据相邻不可逆原则,M->R动作不会发生 根据小压大原则,L->M,M->L只有一个会达标
2.4. 上一步是M->R 根据小压大原则,M->R动作不会重复发生 根据相邻不可逆原则,R->M动作不会发生 根据小压大原则,L->M,M->L只有一个会达标
实际一共4个动作:
- 左->中
- 中->左
- 中->右
- 右->中
可以把中左右抽象成栈
- 左lS
- 中mS
- 右rS
初始化如果没值判断的时候要考虑栈空比较繁琐,因此压入最大值?只需要在循环时考虑到
附件
public static int haonoi(int num,String left,String mid,String right){
Stack<Integer> lS = new Stack<Integer>();
Stack<Integer> mS = new Stack<Integer>();
Stack<Integer> rS = new Stack<>();
lS.push(Integer.MAX_VALUE);
mS.push(Integer.MAX_VALUE);
rS.push(Integer.MAX_VALUE);
for(int i =num;i>0 ; i--) {
lS.push(i);
}
Action[ ] record = {Action.No};
int step = 0;
while(rS.size()!=num + 1){
step += fStackToStack(record,Action.ML,Action.LM,lS,mS,left,mid);
step += fStackToStack(record,Action.LM,Action.ML,mS,lS,mid,left);
step += fStackToStack(record,Action.RM,Action.MR,mS,rS,mid,right);
step += fStackToStack(record,Action.MR,Action.RM,rS,mS,right,mid);
}
return step;
}
private static int fStackToStack(Action[] record, Action preNoAct, Action nowAct, Stack<Integer> fStack, Stack<Integer> tStack, String from, String to) {
if(record[0] != preNoAct && fStack.peek() < tStack.peek()){
tStack.push(fStack.pop());
System.out.println("Move " + tStack.peek() +" from "+from + " to "+ to);
record[0] = nowAct;
return 1;
}
return 0;
}
}
enum Action{
No,
LM,
ML,
MR,
RM
}
。。完全糟糕,我太弱了