Algorithm and Data Structure Interview Guide - Detailed explanation of the classic Tower of Hanoi problem

Tower of Hanoi problem

In both merge sorting and building binary trees, we decompose the original problem into two sub-problems that are half the size of the original problem. However, for the Tower of Hanoi problem, we adopt a different decomposition strategy.

!!! question

给定三根柱子,记为 `A`、`B` 和 `C` 。起始状态下,柱子 `A` 上套着 $n$ 个圆盘,它们从上到下按照从小到大的顺序排列。我们的任务是要把这 $n$ 个圆盘移到柱子 `C` 上,并保持它们的原有顺序不变。在移动圆盘的过程中,需要遵守以下规则。

1. 圆盘只能从一个柱子顶部拿出,从另一个柱子顶部放入。
2. 每次只能移动一个圆盘。
3. 小圆盘必须时刻位于大圆盘之上。

Insert image description here

We will scale as iiThe Tower of Hanoi problem for i is denoted asf ( i ) f(i)f ( i ) . For examplef (3) f(3)f ( 3 ) represents3 3Tower of Hanoi problem with 3 disksAmovingC

Consider the base case

As shown in the figure below, for the problem f (1) f(1)f ( 1 ) , that is, when there is only one disk, weAmove it directly from toC.

=== “<1>”
Insert image description here

=== “<2>”
Insert image description here

As shown in the figure below, for the problem f (2) f(2)f ( 2 ) , that is, when there are two disks,since the small disk must always be on top of the large disk, it is necessary to useBto complete the movement.

  1. AFirst move the upper small disk from to B.
  2. Then move the large disk from Ato C.
  3. Finally move the small disk from Bto C.

=== “<1>”
Insert image description here

=== “<2>”
Insert image description here

=== “<3>”
Insert image description here

=== “<4>”
Insert image description here

Solve problem f (2) f(2)The process of f ( 2 ) can be summarized as:movingthe two disksBfrom toAC. Among them,Cthey are called target columns andBbuffer columns.

Subproblem decomposition

For problem f (3) f(3)f ( 3 ) , i.e. when there are three disks, the situation becomes slightly more complicated.

Because it is known that f ( 1 ) f(1)f ( 1 ) andf (2) f(2)The solution of f ( 2 ) , so we can think from the perspective of divide and conquer,regardAthe two disks at the top as a whole, and perform the steps shown in the figure below. In this way, the three disks are smoothlyAmoved from toC.

  1. Let Bbe the target column and Cbe the buffer column, move the two disks from Ato B.
  2. Move Athe remaining disk in from Adirectly to C.
  3. Let Cbe the target column and Abe the buffer column, move the two disks from Bto C.

=== “<1>”
Insert image description here

=== “<2>”
Insert image description here

=== “<3>”
Insert image description here

=== “<4>”
Insert image description here

Essentially, we take the problem f (3) f(3)f ( 3 ) is divided into two sub-problemsf (2) f(2)f ( 2 ) and subproblemf (1) f(1)f ( 1 ) . After solving these three sub-problems in sequence, the original problem is solved. This shows that the subproblems are independent and the solutions can be combined.

At this point, we can summarize the divide-and-conquer strategy for the Tower of Hanoi problem shown in the figure below: convert the original problem f ( n ) f(n)f ( n ) is divided into two sub-problemsf (n − 1) f(n-1)f(n1 ) and a subproblemf (1) f(1)f ( 1 ) , and solve these three subproblems in the following order.

  1. Put n − 1 n-1n1 diskis movedCfrom to.AB
  2. will remain 1 11 discAis moved directlyC.
  3. Put n − 1 n-1n1 diskis movedAfrom to.BC

For these two subproblems f ( n − 1 ) f(n-1)f(n1 ) ,can be divided recursively in the same wayuntil the minimum subproblemf (1) f(1)f ( 1 ) . Andf ( 1 ) f(1)The solution of f ( 1 ) is known and only requires one shift operation.

Insert image description here

Code

In the code, we declare a recursive function dfs(i, src, buf, tar)that will move srcthe top ii of the barThe i diskbufmoves to the target columntar.

=== “Python”

```python title="hanota.py"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solve_hanota}
```

=== “C++”

```cpp title="hanota.cpp"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

=== “Java”

```java title="hanota.java"
[class]{hanota}-[func]{move}

[class]{hanota}-[func]{dfs}

[class]{hanota}-[func]{solveHanota}
```

=== “C#”

```csharp title="hanota.cs"
[class]{hanota}-[func]{move}

[class]{hanota}-[func]{dfs}

[class]{hanota}-[func]{solveHanota}
```

=== “Go”

```go title="hanota.go"
[class]{}-[func]{move}

[class]{}-[func]{dfsHanota}

[class]{}-[func]{solveHanota}
```

=== “Swift”

```swift title="hanota.swift"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

=== “JS”

```javascript title="hanota.js"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

=== “TS”

```typescript title="hanota.ts"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

=== “Dart”

```dart title="hanota.dart"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

=== “Rust”

```rust title="hanota.rs"
[class]{}-[func]{move_pan}

[class]{}-[func]{dfs}

[class]{}-[func]{solve_hanota}
```

=== “C”

```c title="hanota.c"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

=== “Zig”

```zig title="hanota.zig"
[class]{}-[func]{move}

[class]{}-[func]{dfs}

[class]{}-[func]{solveHanota}
```

As shown in the figure below, the Tower of Hanoi problem forms a height of nnRecursion tree of n , each node represents a sub-problem and corresponds to an opendfs()function,so the time complexity is O ( 2 n ) O(2^n)O(2n ), the space complexity isO ( n ) O(n)O ( n )

Insert image description here

!!! quote

汉诺塔问题源自一种古老的传说故事。在古印度的一个寺庙里,僧侣们有三根高大的钻石柱子,以及 $64$ 个大小不一的金圆盘。僧侣们不断地移动原盘,他们相信在最后一个圆盘被正确放置的那一刻,这个世界就会结束。

然而,即使僧侣们每秒钟移动一次,总共需要大约 $2^{64} \approx 1.84×10^{19}$ 秒,合约 $5850$ 亿年,远远超过了现在对宇宙年龄的估计。所以,倘若这个传说是真的,我们应该不需要担心世界末日的到来。

Guess you like

Origin blog.csdn.net/zy_dreamer/article/details/132911658