【算法模板】动态规划(基础背包篇)—附习题(二)

简介: 【算法模板】动态规划(基础背包篇)—附习题(二)

爬楼梯(进阶)

70. 爬楼梯


题目:


假设你正在爬楼梯。需要 n 阶你才能到达楼顶。


每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?


示例1:


输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶


首先本题是一个非常简单的 DP 问题,我们可以使用一维的 DP数组 来进行求解,且很快就能解出来。但是,如果我们把题目给换一个下—— 将爬楼梯的方法改为1、2、3、4…这样这个就是完全背包问题,且就可以把方法当作物品,楼梯阶数当作背包容量,且满足上诉的第三类模块—dp[i]+=dp[i-num] 且这个就是一个外循环target和内循环nums。OK,接下来我们来看代码解析。

代码部分


Java版本:


class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n + 1];//定义dp数组
        dp[0] = 1;//初始化dp数组,第一个下标值为1
        for (int i = 1; i < n + 1; i++){//外循环target从1开始
            for (int j = 1 ; j < 3 ; j++){//内循环nums
                if (i >= j){//判断如果背包容量大于物品重量则计算共有多少种
                    dp[i] += dp[i - j];
                }
            }
        }
        return dp[n];
    }
}


Python版本:


class Solution:
    def climbStairs(self, n: int) -> int:
        dp = [0] * (n + 1)
        dp[0] = 1
        for i in range(1,n + 1):
            for j in range(1, 3):
                if i >= j :
                    dp[i] += dp[i - j]
        return dp[-1]




组合总和IV

377. 组合总和 Ⅳ


题目:


给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。


题目数据保证答案符合 32 位整数范围。


示例:


输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。


思路:


本题一看就是一个 背包问题 ,拿 target当作背包容量,拿nums的元素当作物品。但是这种背包问题是属于上述的那种类型呢?


这个就需要我们仔细去观察了。在题目中我们能通过 组合 这个字眼能知道本题是上述的 组合类型背包 ,所以我们直接套用组合类型的背包模板即可进行一个秒杀。


注意: 和其他背包模板的顺序不同,背包模板的 target 是外循环,且nums 是内循环!!!因为如果两者反过来则会导致一些组合不会被计算上(不要问我怎么知道的5555)。


代码部分


Java版本:


class Solution {
    public int combinationSum4(int[] nums, int target) {
        int n = nums.length;//首先获取nums数组的长度。
        int[] dp = new int[ target + 1];//创建一个压缩的dp数组(如果不太动压缩的dp数组,可以看参考部分)。
        dp[0] = 1;//初始化dp数组。
        for (int i = 1; i < target + 1 ; i++){//让target作为外循环。
            for (int j = 0 ; j < n ; j++){//让nums作为内循环,且这个一定要是正序(不理解可以去看参考部分)
                int c = nums[j];
                if(i >= c){//进行一个判断,如果背包容量是大于这个物品就需要进行一个累加计算。
                dp[i] += dp[i - c];
                }
            }
        }
        return dp[target];//返回最后的值。
    }
}




Python版本:


#道理和Java版本是一样的,这里我就不再过多的赘述了。
class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
        dp = [0 for i in range(target + 1)]
        dp[0] = 1
        for i in range(target + 1):
            for j in nums :
                if (i >= j):
                    dp[i] +=dp[i - j]
        return dp[-1]


和本题相似的一个题:322. 零钱兑换大家可以去练习练习!




最后一块石头2

1049. 最后一块石头的重量 II


题目:


有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。


每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:


如果 x == y,那么两块石头都会被完全粉碎;

如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x。

最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。


来源:力扣(LeetCode)


示例:


输入:stones = [2,7,4,1,8,1]
输出:1
解释:
组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1],
组合 7 和 8,得到 1,所以数组转化为 [2,1,1,1],
组合 2 和 1,得到 1,所以数组转化为 [1,1,1],
组合 1 和 1,得到 0,所以数组转化为 [1],这就是最优值。


本题相比较于其他题,是一个比较难的一种题,而难点就是在怎么把这个题转化为 背包问题 。其实我们能将石头分为 两 部分,拿其中一部分作为减去另外一部分,则最小的绝对值差值就是我们需要得到的结果,所以我们能拿其中的一部分石头作为 背包容量 ,把stones中的元素作为物品价值,则就可以把本问题转化为了 01背包问题。


代码部分:


Java版本:


class Solution {
    public int lastStoneWeightII(int[] s) {
        int Sum = 0;//统计总和
        for (int i = 0; i < s.length ; i ++ ){
            Sum += s[i];
        }
        int t = Sum / 2;//用sum的一半作为背包容量,也就是说在这个背包能获取的最大子是多少。
        int[] dp = new int[t + 1];//创建dp数组。
        for(int S = 0 ; S < s.length ; S ++){//进行nums外循环。
            for (int j = t ; j >= 0 ; j -- ){//因为是01背包所以需要倒序。
                if (j >= s[S]){//判断背包容量是否是大于物品重量。
                    dp[j] = Math.max(dp[j] , dp[j - s[S]] + s[S]);//套用最大值公式。
                }
            }
        }
        return Sum - dp[t] * 2;//减去两倍就相当于最小差值
    }
}



Python版本:


class Solution:
    def lastStoneWeightII(self, s: List[int]) -> int:
        Sum = sum(s)
        t = Sum // 2
        dp = [0 for i in range(t + 1)]
        for i in s:
            for j in range(t,  0 , -1):
                if j >= i:
                    dp[j] = max(dp[j] ,dp[j - i] + i)
        return Sum - dp[t] * 2



目录
相关文章
|
1月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
8天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
25 2
|
1月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
62 2
动态规划算法学习三:0-1背包问题
|
17天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之顺序表习题精讲【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找习题精讲等具体详解步骤以及举例说明
|
1月前
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
65 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
1月前
|
算法
动态规划算法学习二:最长公共子序列
这篇文章介绍了如何使用动态规划算法解决最长公共子序列(LCS)问题,包括问题描述、最优子结构性质、状态表示、状态递归方程、计算最优值的方法,以及具体的代码实现。
118 0
动态规划算法学习二:最长公共子序列
|
1月前
|
存储 算法
动态规划算法学习一:DP的重要知识点、矩阵连乘算法
这篇文章是关于动态规划算法中矩阵连乘问题的详解,包括问题描述、最优子结构、重叠子问题、递归方法、备忘录方法和动态规划算法设计的步骤。
98 0
|
1月前
|
算法 C++
【算法解题思想】动态规划+深度优先搜索(C/C++)
【算法解题思想】动态规划+深度优先搜索(C/C++)
|
24天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
9天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。