This commit is contained in:
krahets
2026-04-03 18:46:15 +08:00
parent 377736b1bd
commit 9d21ca86b0
352 changed files with 46563 additions and 11262 deletions
+18 -18
View File
@@ -6,56 +6,56 @@ comments: true
!!! question
Input an array $ht$, where each element represents the height of a vertical partition. Any two partitions in the array, along with the space between them, can form a container.
Given an array $ht$, where each element represents the height of a vertical partition. Any two partitions in the array, together with the space between them, can form a container.
The capacity of the container equals the product of height and width (area), where the height is determined by the shorter partition, and the width is the difference in array indices between the two partitions.
The capacity of the container equals the product of its height and width (that is, its area), where the height is determined by the shorter partition and the width is the difference between the array indices of the two partitions.
Please select two partitions in the array such that the capacity of the formed container is maximized, and return the maximum capacity. An example is shown in Figure 15-7.
Select two partitions in the array such that the capacity of the resulting container is maximized, and return that maximum capacity. An example is shown in Figure 15-7.
![Example data for the max capacity problem](max_capacity_problem.assets/max_capacity_example.png){ class="animation-figure" }
<p align="center"> Figure 15-7 &nbsp; Example data for the max capacity problem </p>
The container is formed by any two partitions, **therefore the state of this problem is the indices of two partitions, denoted as $[i, j]$**.
The container is formed by any two partitions, **so the state of this problem is the indices of the two partitions, denoted by $[i, j]$**.
According to the problem description, capacity equals height multiplied by width, where height is determined by the shorter partition, and width is the difference in array indices between the two partitions. Let the capacity be $cap[i, j]$, then the calculation formula is:
According to the problem statement, capacity equals height multiplied by width, where the height is determined by the shorter partition and the width is the difference between the array indices of the two partitions. Let the capacity be $cap[i, j]$; then we obtain the following formula:
$$
cap[i, j] = \min(ht[i], ht[j]) \times (j - i)
$$
Let the array length be $n$, then the number of combinations of two partitions (total number of states) is $C_n^2 = \frac{n(n - 1)}{2}$. Most directly, **we can exhaustively enumerate all states** to find the maximum capacity, with time complexity $O(n^2)$.
Let the array length be $n$. Then the number of ways to choose two partitions (that is, the total number of states) is $C_n^2 = \frac{n(n - 1)}{2}$. The most straightforward approach is to **exhaustively enumerate all states** to find the maximum capacity, which has a time complexity of $O(n^2)$.
### 1. &nbsp; Greedy Strategy Determination
This problem has a more efficient solution. As shown in Figure 15-8, select a state $[i, j]$ where index $i < j$ and height $ht[i] < ht[j]$, meaning $i$ is the short partition and $j$ is the long partition.
This problem has a more efficient solution. As shown in Figure 15-8, consider a state $[i, j]$ where $i < j$ and $ht[i] < ht[j]$. In this case, $i$ is the shorter partition and $j$ is the taller partition.
![Initial state](max_capacity_problem.assets/max_capacity_initial_state.png){ class="animation-figure" }
<p align="center"> Figure 15-8 &nbsp; Initial state </p>
As shown in Figure 15-9, **if we now move the long partition $j$ closer to the short partition $i$, the capacity will definitely decrease**.
As shown in Figure 15-9, **if we now move the taller partition $j$ inward toward the shorter partition $i$, the capacity will definitely decrease**.
This is because after moving the long partition $j$, the width $j-i$ definitely decreases; and since height is determined by the short partition, the height can only remain unchanged ($i$ is still the short partition) or decrease (the moved $j$ becomes the short partition).
This is because after moving the taller partition $j$, the width $j-i$ definitely decreases. Since the height is determined by the shorter partition, the height can only stay the same ($i$ remains the shorter partition) or decrease ($j$ becomes the shorter partition after being moved).
![State after moving the long partition inward](max_capacity_problem.assets/max_capacity_moving_long_board.png){ class="animation-figure" }
<p align="center"> Figure 15-9 &nbsp; State after moving the long partition inward </p>
Conversely, **we can only possibly increase capacity by contracting the short partition $i$ inward**. Because although width will definitely decrease, **height may increase** (the moved short partition $i$ may become taller). For example, in Figure 15-10, the area increases after moving the short partition.
Conversely, **only by moving the shorter partition $i$ inward can the capacity possibly increase**. Although the width will definitely decrease, **the height may increase** (the moved partition at $i$ may be taller). For example, in Figure 15-10, the area increases after moving the shorter partition.
![State after moving the short partition inward](max_capacity_problem.assets/max_capacity_moving_short_board.png){ class="animation-figure" }
<p align="center"> Figure 15-10 &nbsp; State after moving the short partition inward </p>
From this we can derive the greedy strategy for this problem: initialize two pointers at both ends of the container, and in each round contract the pointer corresponding to the short partition inward, until the two pointers meet.
From this, we can derive the greedy strategy for this problem: initialize two pointers at the two ends, and in each round move the pointer corresponding to the shorter partition inward until the two pointers meet.
Figure 15-11 shows the execution process of the greedy strategy.
1. In the initial state, pointers $i$ and $j$ are at both ends of the array.
2. Calculate the capacity of the current state $cap[i, j]$, and update the maximum capacity.
3. Compare the heights of partition $i$ and partition $j$, and move the short partition inward by one position.
4. Loop through steps `2.` and `3.` until $i$ and $j$ meet.
3. Compare the heights of partitions $i$ and $j$, and move the pointer corresponding to the shorter partition inward by one position.
4. Repeat steps `2.` and `3.` until $i$ and $j$ meet.
=== "<1>"
![Greedy process for the max capacity problem](max_capacity_problem.assets/max_capacity_greedy_step1.png){ class="animation-figure" }
@@ -88,9 +88,9 @@ Figure 15-11 shows the execution process of the greedy strategy.
### 2. &nbsp; Code Implementation
The code loops at most $n$ rounds, **therefore the time complexity is $O(n)$**.
The code runs for at most $n$ rounds, **so the time complexity is $O(n)$**.
Variables $i$, $j$, and $res$ use a constant amount of extra space, **therefore the space complexity is $O(1)$**.
Variables $i$, $j$, and $res$ use only a constant amount of extra space, **so the space complexity is $O(1)$**.
=== "Python"
@@ -425,7 +425,7 @@ Variables $i$, $j$, and $res$ use a constant amount of extra space, **therefore
The reason greedy is faster than exhaustive enumeration is that each round of greedy selection "skips" some states.
For example, in state $cap[i, j]$ where $i$ is the short partition and $j$ is the long partition, if we greedily move the short partition $i$ inward by one position, the states shown in Figure 15-12 will be "skipped". **This means that the capacities of these states cannot be verified later**.
For example, in state $cap[i, j]$, suppose $i$ is the shorter partition and $j$ is the taller partition. If we greedily move the shorter partition $i$ inward by one position, the states shown in Figure 15-12 will be "skipped." **This means that their capacities can no longer be checked later**.
$$
cap[i, i+1], cap[i, i+2], \dots, cap[i, j-2], cap[i, j-1]
@@ -435,6 +435,6 @@ $$
<p align="center"> Figure 15-12 &nbsp; States skipped by moving the short partition </p>
Observing carefully, **these skipped states are actually all the states obtained by moving the long partition $j$ inward**. We have already proven that moving the long partition inward will definitely decrease capacity. That is, the skipped states cannot possibly be the optimal solution, **skipping them will not cause us to miss the optimal solution**.
A closer look shows that **these skipped states are exactly the states obtained by moving the taller partition $j$ inward**. We have already proven that moving the taller partition inward will definitely decrease the capacity. Therefore, none of the skipped states can be the optimal solution, **so skipping them does not cause us to miss the optimum**.
The above analysis shows that the operation of moving the short partition is "safe", and the greedy strategy is effective.
The above analysis shows that moving the shorter partition is a "safe" operation, and that the greedy strategy is effective.