用栈来求解hanoi塔问题
题目来源:程序员算法面试指南,牛客网出品;
第一种解法:递归法;
1 //解法一:用递归法; 2 public static int hanoi(int n, String left, String mid, String right){ 3 if(n<1){ 4 return 0; 5 } 6 return process(n, left, mid, right, left, right); 7 } 8 9 public static int process(int n, String left, String mid, String right, String from, String to){ 10 //n=1时,结束条件 11 if(n==1){ 12 //from或to有一个是mid,只需移动1次 13 if(from.equals(mid) || to.equals(mid)){ 14 System.out.println("Move 1 from "+from+" to "+to); 15 return 1; 16 } else{ 17 //from和to都不是mid,需移动2次 18 System.out.println("Move 1 from "+ from + " to "+mid); 19 System.out.println("Move 1 from "+ mid + " to " + to); 20 return 2; 21 } 22 } 23 // n > 1, 24 // from 或 to 有一个是mid, 只需移动一次; 25 if(from.equals(mid)||to.equals(mid)){ 26 String another = (from.equals(left)||to.equals(left))? right : left; 27 int part1 = process(n-1, left, mid, right, from, another); 28 int part2 = 1; 29 System.out.println("Move " + n +" from "+from+" to "+ to); 30 int part3 = process(n-1, left, mid, right, another, to); 31 return part1 + part2 + part3; 32 }else{ 33 // from、to都不是mid, 共需移动5步 34 int part1 = process(n-1, left, mid, right, from, to); 35 int part2 = 1; 36 System.out.println("Move "+ n +" from "+from +" to "+mid); 37 int part3 = process(n-1, left, mid, right, to, from); 38 int part4 = 1; 39 System.out.println("Move "+ n +" from "+mid +" to "+to); 40 int part5 = process(n-1, left, mid, right, from, to); 41 return part1 + part2 + part3 + part4 + part5; 42 } 43 }
第二种解法:用栈模拟
1 //第二种解法 2 //用栈模拟 3 public static int hanoi(int n){ 4 Stack<Integer> LS = new Stack<Integer>(); 5 Stack<Integer> MS = new Stack<Integer>(); 6 Stack<Integer> RS = new Stack<Integer>(); 7 8 for(int i=n; i>0; i--) 9 LS.push(i); 10 11 int counter = 1; //记录移动次数 12 int last_step = 1; //记录前一次移动,1:从左边移到中间,2:从中间移到左边,3:从中间移动到右边,4:从右边移动到中间 13 MS.push(LS.pop()); //第一次,必须是左边往中间移动 14 System.out.println("Move 1 from left to mid"); 15 16 while(RS.size() != n){ 17 for(int this_step=1; this_step<5; this_step++){ //步骤循环,判断哪种是正确的移动步骤,每次只有一种正确移法; 18 //当前步,不能跟上一步重复,也不能跟上一步相反(浪费移动步数) 19 if(this_step == last_step || 20 this_step + last_step == 3 || this_step + last_step == 7) 21 continue; 22 switch (this_step){ 23 case 1: //从左边移动到中间 24 if(LS.empty()) break; //如果左边栈是空的,则不能进行移动 25 if(MS.empty() || LS.peek() < MS.peek()){ //如果中间栈为空,则不需要判断后边的,否则MS.peek()会报错 26 MS.push(LS.pop()); 27 System.out.println("Move " + MS.peek() + " from left to mid."); 28 counter++; 29 last_step = this_step; //当前步在下一次移动时成为上一步 30 } 31 break; 32 case 2: 33 if(MS.empty()) break; 34 if(LS.empty() || MS.peek() < LS.peek()){ 35 LS.push(MS.pop()); 36 System.out.println("Move " + LS.peek() + " from mid to left."); 37 counter ++; 38 last_step = this_step; 39 } 40 break; 41 case 3: 42 if(MS.empty()) break; 43 if(RS.empty() || MS.peek() < RS.peek()){ 44 RS.push(MS.pop()); 45 System.out.println("Move "+ RS.peek() + " from mid to right."); 46 counter ++; 47 last_step = this_step; 48 } 49 break; 50 case 4: 51 if(RS.empty()) break; 52 if(MS.empty() || MS.peek() > RS.peek()){ 53 MS.push(RS.pop()); 54 System.out.println("Move "+ MS.peek() + " from right to mid."); 55 counter++; 56 last_step = this_step; 57 } 58 break; 59 default: 60 System.out.println("step choice error!"); 61 } 62 } 63 } 64 return counter; 65 }