There are n
uniquely-sized sticks whose lengths are integers from 1
to n
. You want to arrange the sticks such that exactly k
sticks are visible from the left. A stick is visible from the left if there are no longer sticks to the left of it.
[1,3,2,5,4]
, then the sticks with lengths 1
, 3
, and 5
are visible from the left.Given n
and k
, return the number of such arrangements. Since the answer may be large, return it modulo 109 + 7
.
Example 1:
Input: n = 3, k = 2 Output: 3 Explanation: [1,3,2], [2,3,1], and [2,1,3] are the only arrangements such that exactly 2 sticks are visible. The visible sticks are underlined.
Example 2:
Input: n = 5, k = 5 Output: 1 Explanation: [1,2,3,4,5] is the only arrangement such that all 5 sticks are visible. The visible sticks are underlined.
Example 3:
Input: n = 20, k = 11 Output: 647427950 Explanation: There are 647427950 (mod 109 + 7) ways to rearrange the sticks such that exactly 11 sticks are visible.
Constraints:
1 <= n <= 1000
1 <= k <= n
This problem asks to find the number of ways to arrange n
uniquely-sized sticks (lengths 1 to n) such that exactly k
sticks are visible from the left. A stick is visible if no longer sticks are to its left.
The most efficient approach is using dynamic programming.
1. Dynamic Programming Approach (with space optimization):
State: dp[i][j]
represents the number of arrangements of i
sticks where j
sticks are visible.
Base Case: dp[0][0] = 1
(no sticks, no visible sticks).
Recurrence Relation: To calculate dp[i][j]
, consider two cases for the i
-th stick (the longest stick):
Case 1: The i
-th stick is visible. If it's visible, it must be the leftmost stick. The remaining i-1
sticks must have j-1
visible sticks. Therefore, we add dp[i-1][j-1]
to our count.
Case 2: The i
-th stick is not visible. This means it's placed somewhere among the other i-1
sticks. There are i-1
possible positions for this stick. For each position, we still need to arrange the other i-1
sticks such that j
sticks are visible. So we add (i-1) * dp[i-1][j]
.
Final Result: The final answer is dp[n][k]
.
2. Space Optimization:
We can optimize the space complexity by observing that dp[i][j]
only depends on the previous row (i-1
). Therefore, we can use a 1D array to store the current row, reducing space from O(n*k) to O(k). The iterative calculation updates the array in-place.
Time and Space Complexity:
Time Complexity: O(n*k) due to the nested loops in the dynamic programming solution. We iterate through all possible numbers of sticks and visible sticks.
Space Complexity: O(k) after space optimization. We only need a 1D array of size k
to store the DP states.
Code Implementation (Python with space optimization):
def rearrangeSticks(n: int, k: int) -> int:
mod = 10**9 + 7
dp = [0] * (k + 1) # 1D DP array
dp[0] = 1 # Base case
for i in range(1, n + 1):
new_dp = [0] * (k + 1) # Temporary array to store new row
for j in range(1, k + 1):
new_dp[j] = (dp[j - 1] + (i - 1) * dp[j]) % mod
dp = new_dp # Update dp to the new row
return dp[k]
The code in other languages (Java, C++, Go, TypeScript) follows a similar structure and logic, employing the space-optimized 1D DP array for efficient calculation. The modulo operation (% mod
) ensures that the result remains within the specified range.