左神算法:用栈来求解限制后的汉诺塔问题(Java版)
生活随笔
收集整理的這篇文章主要介紹了
左神算法:用栈来求解限制后的汉诺塔问题(Java版)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本題來自左神《程序員面試代碼指南》“用棧來求解漢諾塔問題”題目。
題目
限制后的漢諾塔問題如下:
限制不能從最左側的塔直接移動到最右側,也不能從最右側直接移動到最左側,而是必須經過中間
求當塔有N層的時候,打印最優移動過程和最優移動總步數
題解
用以下兩種方法解決:
- 方法1:遞歸方法。本文只提供代碼,具體的問題解析請參考原書。
- 方法2:非遞歸,用棧來模擬漢諾塔的三個塔。本文詳細說明此方法。
代碼
為了便于理解,本文對 解法 2 做了詳細的注釋。
import java.util.Stack;public class Main {public static void main(String[] args) {int num = 4;// solution 1:遞歸解法int steps1 = hanoiProblem1(num, "left", "mid", "right");System.out.println("It will move " + steps1 + " steps.");System.out.println("===================================");// solution 2:非遞歸,用棧模擬整個過程int steps2 = hanoiProblem2(num, "left", "mid", "right");System.out.println("It will move " + steps2 + " steps.");System.out.println("===================================");}/*** 解法 1*/public static int hanoiProblem1(int num, String left, String mid,String right) {if (num < 1) {return 0;}return process(num, left, mid, right, left, right);}public static int process(int num, String left, String mid, String right,String from, String to) {if (num == 1) {if (from.equals(mid) || to.equals(mid)) {System.out.println("Move 1 from " + from + " to " + to);return 1;} else {System.out.println("Move 1 from " + from + " to " + mid);System.out.println("Move 1 from " + mid + " to " + to);return 2;}}if (from.equals(mid) || to.equals(mid)) {String another = (from.equals(left) || to.equals(left)) ? right : left;int part1 = process(num - 1, left, mid, right, from, another);int part2 = 1;System.out.println("Move " + num + " from " + from + " to " + to);int part3 = process(num - 1, left, mid, right, another, to);return part1 + part2 + part3;} else {int part1 = process(num - 1, left, mid, right, from, to);int part2 = 1;System.out.println("Move " + num + " from " + from + " to " + mid);int part3 = process(num - 1, left, mid, right, to, from);int part4 = 1;System.out.println("Move " + num + " from " + mid + " to " + to);int part5 = process(num - 1, left, mid, right, from, to);return part1 + part2 + part3 + part4 + part5;}}/*** 解法 2:重要*/public static enum Action {No, LToM, MToL, MToR, RToM}public static int hanoiProblem2(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<Integer>(); // 右棧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}; // 初始化 上一個動作為 No Actionint step = 0;while (rS.size() != num + 1) { // 每走一步,這4個動作只會有一個達標(不要誤解,這并不意味著每一次循環step只會+1,因為你走完一步之后,可能仍停留在當前這輪循環中),因此循環考察這4個動作即可step += fStackTotStack(record, Action.MToL, Action.LToM, lS, mS, left, mid); // 判斷當前是否可執行 L->M 動作step += fStackTotStack(record, Action.LToM, Action.MToL, mS, lS, mid, left);step += fStackTotStack(record, Action.RToM, Action.MToR, mS, rS, mid, right);step += fStackTotStack(record, Action.MToR, Action.RToM, rS, mS, right, mid);}return step;}/*** 判斷當前動作是否可以執行** @param record 實際的上一個動作* @param preNoAct 上一個動作不能是此動作* @param nowAct 當前要做的動作* @param fStack fromStack,當前欲從哪個棧彈出元素* @param tStack toStack,當前欲將彈出的元素壓入到哪個棧* @param from 從哪個棧(字符串),用于打印* @param to 到哪個棧(字符串),用于打印* @return 是否執行了這一動作*/public static int fStackTotStack(Action[] record, Action preNoAct,Action nowAct, Stack<Integer> fStack, Stack<Integer> tStack,String from, String to) {if (record[0] != preNoAct && fStack.peek() < tStack.peek()) { // 同時滿足:(1)不可逆原則 && (2)小壓大原則tStack.push(fStack.pop()); // 執行本次動作System.out.println("Move " + tStack.peek() + " from " + from + " to " + to);record[0] = nowAct;return 1;}return 0; // 不滿足兩原則,不執行本次動作} }總結
以上是生活随笔為你收集整理的左神算法:用栈来求解限制后的汉诺塔问题(Java版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微服务、容器、DevOps三者之间的演进
- 下一篇: 左神算法:生成窗口最大值数组(Java版