题目描述
给定一个数组arr,长度为N,arr中的值只有1,2,3三种
- arr[i] == 1,代表汉诺塔问题中,从上往下第i个圆盘目前在左
- arr[i] == 2,代表汉诺塔问题中,从上往下第i个圆盘目前在中
- arr[i] == 3,代表汉诺塔问题中,从上往下第i个圆盘目前在右
那么arr整体就代表汉诺塔游戏过程中的一个状况
如果这个状况不是汉诺塔最优解运动过程中的状况,返回-1
如果这个状况是汉诺塔最优解运动过程中的状况,返回它是第几个状况
题目解析
问题:完成 i i i层汉诺塔一共需要几步
假设一共有三个柱子:from、to、other
对于 i i i层汉诺塔,整个移动过程可以分为三步:
- 第一步: 将 [ 1 , i − 1 ] [1,i-1] [1,i−1]从from移动到mid
- 第二步:将 [ i ] [i] [i]从from移动到to
- 第三步:将 [ 1 , i − 1 ] [1,i-1] [1,i−1]从mid移动到to
从上面三个部分可以知道
s
[
i
]
=
s
[
i
−
1
]
+
1
+
s
[
i
−
1
]
s[i] = s[i - 1] + 1 + s[i - 1]
s[i]=s[i−1]+1+s[i−1]
化简后可得等比数列:
s
(
i
)
=
2
s
(
i
−
1
)
+
1
s(i) = 2s(i - 1) + 1
s(i)=2s(i−1)+1
用数学归纳法得出结论:👇
s
(
i
)
=
2
i
−
1
−
1
s(i) = 2^{i - 1} - 1
s(i)=2i−1−1
3层汉诺塔,用了7步,每一步都走最优解的话,那我们步数就是2^i-1步
class Solution {
public:
int f(int i, int from, int to, int other){
if (i == -1) return 0;//没有盘子了,不走,返回0步
//否则还有盘子,0号盘是最小盘子
int step1 = f(i - 1, from, other, to); //走第1)步
int step2 = 1;//完成2)
int step3 = f(i - 1, other, to, from);//完成3)
return step1 + step2 + step3;
}
int bestStepHanNuo(int N){
if (N == 0) return 0;//没有盘子不走
if (N == 1) return 1;//一个盘子,走一步到位
return f(N - 1, 1, 3, 2);//将0--N-1号盘子从1搬到3,将2作为中转,最优解是多少步???
}
};
当前是第几步
3层汉诺塔
- arr=111,表示汉诺塔问题最开始状态都在1棍子上,这是第0步
- arr=311,表示汉诺问题第1步,0号盘放到了3棍子上
- arr=321,表示汉诺塔问题第2步,1号盘放到了2棍子上
- ……
- arr=333,这个arr是汉诺塔问题的第2^3-1步
问题:那么现在来到了i号盘,我们让i盘子去哪里?
- 如果是最优解,此时我们已经让 i − 1 i - 1 i−1层汉诺塔到了other了,那么必须让它去to,这就是最优解,i非要去other绕弯子,返回-1,不合法的。
现在我们定义一个函数 f ( a r r , i , f r o m , t o , o t h e r ) f(arr,i,from,to,other) f(arr,i,from,to,other):arr状态带着,i+1层汉诺塔问题,0–i为编号,把i+1层全部搬到to上,看看arr是最优解的第几步?
此时我们来看 i i i号盘在哪里
- 如果 i i i在 o t h e r other other上,那么不是最接解,return -1
- 如果
i
i
i在
f
r
o
m
from
from上,也就是在汉诺塔的第一步了
- 它还需要完成1),然后2)才能去完成3)
- 也就是需要将i-1搬到other,即 f ( a r r , i − 1 , f r o m , o t h e r , t o ) f(arr,i-1,from,other,to) f(arr,i−1,from,other,to)
- 如果
i
i
i在
t
o
to
to上
- 也就是2)已经完成了,需要完成3)然后统计步数返回
class Solution {
public:
int process(std::vector<int>arr ,int i, int from, int to, int other){
if (i == -1) return 0;//没有盘子了,不走,返回0步
//否则还有盘子,0号盘是最小盘子
if (arr[i] == other) {
return -1;
}
if (arr[i] == from) {//i竟然还在from,说明这1)也没有搞定,需要先搞定1)
return process(arr, i - 1, from, to, other);
} else { // arr[i] == to
// 已经走完1,2两步了,
int p1 = (1 << i) - 1;
int p2 = 1;
int p3 = process(arr, i - 1, other, to, from);
if (p3 == -1) {
return -1;
}
return p1 + p2 + p3;
}
}
int bestStepHanNuo(std::vector<int> arr){
int N = arr.size();
return process(arr, N - 1, 1, 3, 2);
}
};