Given n
points on a 1-D plane, where the ith
point (from 0
to n-1
) is at x = i
, find the number of ways we can draw exactly k
non-overlapping line segments such that each segment covers two or more points. The endpoints of each segment must have integral coordinates. The k
line segments do not have to cover all n
points, and they are allowed to share endpoints.
Return the number of ways we can draw k
non-overlapping line segments. Since this number can be huge, return it modulo 109 + 7
.
Example 1:
Input: n = 4, k = 2 Output: 5 Explanation: The two line segments are shown in red and blue. The image above shows the 5 different ways {(0,2),(2,3)}, {(0,1),(1,3)}, {(0,1),(2,3)}, {(1,2),(2,3)}, {(0,1),(1,2)}.
Example 2:
Input: n = 3, k = 1 Output: 3 Explanation: The 3 ways are {(0,1)}, {(0,2)}, {(1,2)}.
Example 3:
Input: n = 30, k = 7 Output: 796297179 Explanation: The total number of possible ways to draw 7 line segments is 3796297200. Taking this number modulo 109 + 7 gives us 796297179.
Example 4:
Input: n = 5, k = 3 Output: 7
Example 5:
Input: n = 3, k = 2 Output: 1
Constraints:
2 <= n <= 1000
1 <= k <= n-1
Solution 1: Naive DP (TLE)
dp[n][k] := ans of problem(n, k)
dp[n][1] = n * (n – 1) / 2 # C(n,2)
dp[n][k] = 1 if k == n – 1
dp[n][k] = 0 if k >= n
dp[n][k] = sum((i – 1) * dp(n – i + 1, k – 1) 2 <= i < n
Time complexity: O(n^2*k)
Space complexity: O(n*k)
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Solution { public: int numberOfSets(int n, int k) { constexpr int kMod = 1e9 + 7; vector<vector<int>> cache(n + 1, vector<int>(k + 1)); function<int(int, int)> dp = [&](int n, int k) { if (k >= n) return 0; if (k == 1) return n * (n - 1) / 2; if (k == n - 1) return 1; int& ans = cache[n][k]; if (ans) return ans; for (long i = 2; i < n; ++i) { const int t = ((i - 1) * dp(n - i + 1, k - 1)) % kMod; ans = (ans + t) % kMod; } return ans; }; return dp(n, k); } }; |
Solution 2: DP w/ Prefix Sum
Time complexity: O(nk)
Space complexity: O(nk)
Python3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Author: Huahua 940 ms class Solution: def numberOfSets(self, n: int, k: int) -> int: kMod = 10**9 + 7 dp = [[0] * (k + 1) for _ in range(n + 1)] for i in range(n + 1): dp[i][0] = 1 for j in range(1, k + 1): s = 0 for i in range(1, n + 1): dp[i][j] = (s + dp[i - 1][j]) s += dp[i][j - 1] return dp[n][k] % kMod |
Solution 3: DP / 3D State
Time complexity: O(nk)
Space complexity: O(nk)
Python3
1 2 3 4 5 6 7 8 9 10 11 |
# Author: Huahua 940 ms class Solution: def numberOfSets(self, n: int, k: int) -> int: kMod = 10**9 + 7 @lru_cache(None) def dp(n: int, k: int, e: int) -> int: if k == 0: return 1 if k > n: return 0 return (dp(n - 1, k, e) + dp(n + e - 1, k - e, 1 - e)) % kMod return dp(n, k, 0) |
Solution 4: DP / Mathematical induction
Time complexity: O(nk)
Space complexity: O(nk)
Python3
1 2 3 4 5 6 7 8 9 10 11 |
# Author: Huahua 648 ms class Solution: def numberOfSets(self, n: int, k: int) -> int: @lru_cache(None) def dp(n: int, k: int) -> int: if k >= n: return 0 if k == 1: return n * (n - 1) // 2 if k == n - 1: return 1 return 2 * dp(n - 1, k) - dp(n - 2, k) + dp(n - 1, k - 1) return dp(n, k) % (10**9 + 7) |
Solution 5: DP / Reduction
This problem can be reduced to: given n + k – 1 points, pick k segments (2*k points).
if two consecutive points were selected by two segments e.g. i for A and i+1 for B, then they share a point in the original space.
Answer C(n + k – 1, 2*k)
Time complexity: O((n+k)*2) Pascal’s triangle
Space complexity: O((n+k)*2)
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Solution { public: int numberOfSets(int n, int k) { constexpr int kMod = 1e9 + 7; vector<vector<int>> dp(n + k , vector<int>(n + k)); for (int i = 0; i < n + k; ++i) { dp[i][0] = dp[i][i] = 1; for (int j = 1; j < i; ++j) dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % kMod; } return dp[n + k - 1][2 * k]; } }; |
请尊重作者的劳动成果,转载请注明出处!花花保留对文章/视频的所有权利。
如果您喜欢这篇文章/视频,欢迎您捐赠花花。
If you like my articles / videos, donations are welcome.
Be First to Comment