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.
- For example, if the sticks are arranged
[1,3,2,5,4]
, then the sticks with lengths1
,3
, and5
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
If using the commented out logic, the runtime will be O(N^3) instead of O(N^2). The key observation here is that if we try to arrange sticks from the right side, out of all the available sticks to choose from, the tallest one is always visible, it also always blocks all the shorter sticks to its right. So if we are given a subproblem of having n sticks to choose from and wanting to get k visible sticks, we either put the tallest on the right most position, which reduce to subproblem (n - 1, k - 1); Or we put any sticks that is not the tallest (there are n - 1 options), which reduce to subproblem (n - 1, k).
class Solution { private long[][] dp; private int mod = (int)1e9 + 7; public int rearrangeSticks(int n, int k) { dp = new long[n + 1][k + 1]; for(int i = 0; i <= n; i++) { Arrays.fill(dp[i], -1); } for(int i = 0; i <= k; i++) { dp[i][i] = 1; } for(int i = 1; i <= n; i++) { dp[i][0] = 0; } compute(n, k); return (int)(dp[n][k]); } private long compute(int n, int k) { if(dp[n][k] >= 0) { return dp[n][k]; } dp[n][k] = 0; dp[n][k] = (dp[n][k] + compute(n - 1, k - 1)) % mod; dp[n][k] = (dp[n][k] + compute(n - 1, k) * (n - 1) % mod) % mod; // long p = n - 1; // for(int m = n - 2; m >= k - 1; m--) { // dp[n][k] = (dp[n][k] + compute(m, k - 1) * p % mod) % mod; // p = p * m % mod; // } return dp[n][k]; } }