LeetCode习题:汉诺塔问题

题目描述:在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时受到以下限制:

  • (1) 每次只能移动一个盘子;
  • (2) 盘子只能从柱子顶端滑出移到下一根柱子;
  • (3) 盘子只能叠在比它大的盘子上。

请编写程序,用栈将所有盘子从第一根柱子移到最后一根柱子。你需要原地修改栈。

示例:

例1
    输入:A = [2, 1, 0], B = [], C = []
    输出:C = [2, 1, 0]
    
例2
    输入:A = [1, 0], B = [], C = []
    输出:C = [1, 0]

提示:A中盘子的数目不大于14个。

解题思路:通过纸和笔进行实际的“搬运”工作

1. A盘中数目为0,无需搬运, 操作步数为:0(2^0 - 1)
2. A盘中数目为1,A->C,操作步数为:1(2^1-1)
3. A盘中数目为2,需要将A盘中最上面的圆盘先放入B柱,然后将A盘中底部大圆盘放入C,然后再将B中的小圆盘放入C即完成,即 A->B, A->C, B->C, 操作步数为:3(2^2-1)
4. 同理,A盘中数目为3时,A->C, A->B, C->B, A->C, B->A, B->C, A->C, 操作步数为:7(2^3-1)
...

通过以上步骤我们发现,回顾整个搬运过程,如果想将n个从小到大排列的圆盘从A柱搬运到C柱,并且保持排列顺序不变,需要先将A柱上面的n-1个圆盘经过C柱的搬运到B柱上,也就是说,将A柱最大圆盘搬运到C柱的时候,此时B柱上是从小到大排列的n-1个圆盘,即可以将A柱最大圆盘搬运到C柱的时刻,三根柱子的情况是:A柱剩最大圆盘,B柱n-1圆盘(从小到大排列),C柱为空,这样就可以想象成: A(n-1)->B, A->C, B->C,其中A(n-1)->B过程需要经过C柱, B->C过程需要经过A柱

解题语言: Swift

class Solution {
    func hanota(_ A: inout [Int], _ B: inout [Int], _ C: inout [Int]) {
        let n = A.count
        recursion(&A, &B, &C, n)
    }

    func recursion(_ A: inout [Int], _ B: inout [Int], _ C: inout [Int], _ n: Int) {
        if n <= 0 {
            return
        }
        if n == 1 {
            let val = A.removeLast()
            C.append(val)
            return
        }
        //将A上面的 n-1 个圆盘经由 C 移到 B
        recursion(&A, &C, &B, n - 1)
        //将A最底部的盘移动到C
        let val = A.removeLast()
        C.append(val)
        //将B上面的 n-1 个圆盘经 A 移动到 C
        recursion(&B, &A, &C, n - 1)
    }
}

复杂度分析:

时间复杂度:O(2n),其中n为圆盘数目,因为将n个圆盘从A->C需要经过2n-1步
空间复杂度: O(n), 其中n为圆盘数目,空间复杂度主要取决于递归调用的栈空间,因为递归需要保存调用栈,直至递归完成,递归最大深度为n,
题目来源:LeetCode

你可能感兴趣的:(LeetCode习题:汉诺塔问题)