leetcode
leetcode 2801 ~ 2850
汉诺塔问题

汉诺塔问题

难度:

标签:

题目描述

In the classic problem of the Towers of Hanoi, you have 3 towers and N disks of different sizes which can slide onto any tower. The puzzle starts with disks sorted in ascending order of size from top to bottom (i.e., each disk sits on top of an even larger one). You have the following constraints:

(1) Only one disk can be moved at a time.
(2) A disk is slid off the top of one tower onto another tower.
(3) A disk cannot be placed on top of a smaller disk.

Write a program to move the disks from the first tower to the last using stacks.

Example1:

 Input: A = [2, 1, 0], B = [], C = []
 Output: C = [2, 1, 0]

Example2:

 Input: A = [1, 0], B = [], C = []
 Output: C = [1, 0]

Note:

  1. A.length <= 14

代码结果

运行时间: 16 ms, 内存: 16.1 MB


/*
 * 思路:
 * 1. 使用 Java Stream API 是不太可能直接实现递归逻辑,但可以使用 Stream 处理一些数据。
 * 2. 这里的代码更适合用传统方式实现递归来处理汉诺塔问题。
 */

import java.util.Stack;
import java.util.stream.Stream;

public class HanoiTowerStream {
    public void hanoi(int n, Stack<Integer> from, Stack<Integer> to, Stack<Integer> aux) {
        if (n == 0) return;
        hanoi(n - 1, from, aux, to);
        to.push(from.pop());
        hanoi(n - 1, aux, to, from);
    }

    public static void main(String[] args) {
        Stack<Integer> A = new Stack<>();
        Stack<Integer> B = new Stack<>();
        Stack<Integer> C = new Stack<>();
        Stream.of(2, 1, 0).forEach(A::push);
        new HanoiTowerStream().hanoi(A.size(), A, C, B);
        System.out.println(C);
    }
}

解释

方法:

本题解采用了经典的递归方法来解决汉诺塔问题。递归方法分为几个步骤:1. 将顶部的n-1个盘子从源柱子A使用辅助柱子C移动到目标柱子B。2. 将最大的盘子直接从源柱子A移动到目标柱子C。3. 最后,将那n-1个盘子从B通过A移动到C。递归的基础情况是当只有一个盘子时,直接将其从A移动到C。

时间复杂度:

O(2^n)

空间复杂度:

O(n)

代码细节讲解

🦆
在递归解决汉诺塔问题中,为何选择将n-1个盘子先移动到辅助柱子B而不是直接到目标柱子C?
在汉诺塔问题中,移动n-1个盘子到辅助柱子B是为了释放最大的盘子,并将其直接从源柱子A移动到目标柱子C。如果直接尝试将n-1个盘子移动到目标柱子C,那么最大的盘子将无法直接移动到C,因为它被其他较小的盘子所阻挡。因此,先将n-1个盘子移动到B,然后移动最大盘子到C,最后将这n-1个盘子从B移动到C,这样可以确保按正确顺序和规则解决问题。
🦆
递归函数中,`self.hanota(A[1:], C, B)`这一行代码的具体含义是什么?如何理解此处的递归调用?
代码`self.hanota(A[1:], C, B)`的含义是将列表A中除了最后一个元素之外的所有元素视为一个独立的子问题,并使用C作为辅助柱子,B作为目标柱子来递归解决这个子问题。此处的递归调用是基于汉诺塔问题的可归约性:解决包含n个盘子的问题可以通过先解决n-1个盘子的问题来简化。这里A[1:]表示除去最底下盘子后的所有盘子,递归地先将它们从A移到B,以便可以处理最底下的最大盘子。
🦆
特别是对于边界情况,当A中只有一个盘子时,解决方案是什么样的?这是否考虑了所有可能的边界情况?
当A中只有一个盘子时,解决方案是直接将这个盘子从A移到C。这是递归的基础情况。在代码中,如果A的长度为1,就将A的元素移到C,并从A中移除这个元素。这考虑了汉诺塔递归算法的所有可能边界情况,因为这是最简单的情景,即只有一个盘子需要移动,不需要进一步递归。这样确保了算法的正确终止和功能完整性。

相关问题