📌  相关文章
📜  不包含相邻元素的子集计数(1)

📅  最后修改于: 2023-12-03 15:21:30.799000             🧑  作者: Mango

不包含相邻元素的子集计数

问题描述

给定一个由 n 个正整数组成的序列,你需要选出一些数字,使得这些数字互不相邻,求所有方案数。

例如,当 n=4 且序列为 {1,2,1,3} 时,所有可行方案为 {1,3}{2,3},共有两种方案。

解法
动态规划

设 $f_i$ 表示只考虑前 $i$ 个数字,选出一些数字使得它们互不相邻的方案数,$a_i$ 表示第 $i$ 个数字的权值(即选择它所得的收益),则有动态转移方程:

$$f_i=\max{f_{i-1},f_{i-2}+a_i}$$

其中,$f_{i-1}$ 表示不选择第 $i$ 个数字,$f_{i-2}+a_i$ 表示选择第 $i$ 个数字。

需要注意的是,初始状态为 $f_0=0$、$f_1=a_1$。

根据上述动态转移方程,从前往后依次计算 $f_i(i=2,3,\cdots,n)$ 的值,最终得到所求的答案 $f_n$。

时间复杂度为 $O(n)$。

代码实现
def count_subsets(nums: List[int]) -> int:
    n = len(nums)
    if n < 2:  # 特判
        return n
    dp = [0] * (n + 1)  # 数组初始化
    dp[1] = nums[0]
    for i in range(2, n + 1):
        dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1])
    return dp[n]
int count_subsets(vector<int>& nums)
{
    int n = nums.size();
    if (n < 2) {  // 特判
        return n;
    }
    // 数组初始化
    vector<int> dp(n + 1, 0);
    dp[1] = nums[0];
    for (int i = 2; i <= n; ++i) {
        dp[i] = max(dp[i - 1], dp[i - 2] + nums[i - 1]);
    }
    return dp[n];
}
参考链接

LeetCode 198. House Robber