LeetCode每日一题(1621. Number of Sets of K Non-Overlapping Line Segments)

给定平面上n个点,求出能形成k个非重叠线段的所有组合方式,线段端点必须是整数坐标。返回组合数对10^9 + 7取模的结果。例如,n=4, k=2时有5种不同的组合。题目通过动态规划解决,区分线段为空或连接的状态,递推求解总数。" 118342467,11109711,Spring Native与GraalVM:构建原生镜像,"['Java', 'Spring Boot', 'Spring', 'Serverless', 'GraalVM']

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.

Constraints:

  • 2 <= n <= 1000
  • 1 <= k <= n-1

首先这题我们要按线段来看, n 个点分割出 n-1 个线段, 每个线段要么是线, 要么是空。
假设 dp[n][k][0]是第 n 条线段为空时且此时一共有 k 条线的情况的组合数量, dp[n][k][1]是第 n 条线段为线且此时一共有 k 条线的情况的组合数量, 我们不难推出, dp[n][k][0] = dp[n-1][k][0] + dp[n-1][k][1], 也就是前一个线段时不管是空还是线,已存在 k 条线的组合数量, 之所以需要 n-1 时就完成 k 条线是因为此时考虑的是第 n 段为空的情况。第 n 段为线的情况是 dp[n][k][1] = dp[n-1][k-1][0] + dp[n-1][k-1][1] + dp[n-1][k][1], 这里面 dp[n-1][k-1][0]是第 n-1 段为空且有 k-1 条线的情况, dp[n-1][k-1][1]是第 n-1 段为线且有 k-1 条线的情况, 这两个比较好理解,就是到第 n-1 段为止已经完成了 k-1 条线,第 n 段作为一条长度为 1 的独立的线加入。dp[n-1][k][1]所考虑的情况是第 n-1 段已经有了 k 条线而且第 n-1 段为线的情况,此时第 n 段为线,但不是独立的线,是跟 n-1 这一段融合的线,看做是 n-1 段的延长

这题中等难度,但是做出来还是挺有成就感的



static M: i64 = 1000000007;

impl Solution {
    pub fn number_of_sets(n: i32, k: i32) -> i32 {
        let mut dp = vec![vec![vec![0, 0]; k as usize + 1]; n as usize - 1];
        dp[0][0][0] = 1;
        dp[0][1][1] = 1;
        for i in 1..n as usize - 1 {
            dp[i][0][0] = 1;
            for j in 1..k as usize + 1 {
                dp[i][j][0] = (dp[i - 1][j][0] + dp[i - 1][j][1]) % M;
                dp[i][j][1] = (dp[i - 1][j - 1][0] + dp[i - 1][j - 1][1] + dp[i - 1][j][1]) % M;
            }
        }
        ((dp[n as usize - 2][k as usize][0] + dp[n as usize - 2][k as usize][1]) % M) as i32
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值