动态规划、贪心算法、分治法

文章目录

在算法设计中,贪心算法(Greedy Algorithms)、动态规划与分治法(Divide and Conquer)并列,是最基础、最重要的算法设计思想。

贪心算法

动态规划

小偷背包示例

knapsack是背包的意思。

代码:

java 复制代码
public class Knapsack01 {

    /**
     * 0-1 背包问题求解
     * @param W 背包的总容量
     * @param w 每个物品的重量数组
     * @param v 每个物品的价值数组
     * @return 背包能装下的最大价值
     */
    public static int knapsack(int W, int[] w, int[] v) {
        int n = w.length; // 物品的总个数
        
        // 1. 定义状态数组:dp[i][j] 表示前 i 个物品在容量为 j 时的最大价值
        // 行数是 n+1(包含0个物品的情况),列数是 W+1(包含容量为0的情况)
        int[][] dp = new int[n + 1][W + 1];

        // 2. 遍历物品(相当于填表的行)
        // 从第 1 个物品开始,直到第 n 个物品
        for (int i = 1; i <= n; i++) {
            
            // 3. 遍历背包容量(相当于填表的列)
            // 从容量 0 一直遍历到最大容量 W
            for (int j = 0; j <= W; j++) {
                
                // 核心决策:小偷面对第 i 个物品时的二选一
                if (j < w[i - 1]) {
                    // 情况 A:当前背包容量 j 小于物品重量 w[i-1]
                    // 小偷装不下这个物品,只能放弃。
                    // 此时的最大价值等于【没有这个物品时】的最大价值
                    dp[i][j] = dp[i - 1][j]; 
                } else {
                    // 情况 B:当前背包容量 j 大于等于物品重量 w[i-1]
                    // 小偷可以装下,此时需要比较"装"与"不装"哪个更划算
                    int notTake = dp[i - 1][j]; // 不装:继承上一行的结果
                    int take = dp[i - 1][j - w[i - 1]] + v[i - 1]; // 装:当前物品价值 + 剩余空间的最优解
                    
                    // 取两者中的最大值
                    dp[i][j] = Math.max(notTake, take); 
                }
            }
        }

        // 4. 返回最终结果:表格右下角的值,即前 n 个物品在容量 W 下的最大价值
        return dp[n][W];
    }

    // 测试代码
    public static void main(String[] args) {
        int W = 5; // 背包容量为 5
        int[] weights = {2, 3, 4}; // 物品重量
        int[] values = {3, 4, 5};  // 物品价值

        int maxValue = knapsack(W, weights, values);
        System.out.println("小偷能偷到的最大价值是: " + maxValue);
    }
}

代码与表格的对应关系

1、i对应表格的行(第几个物品)。注意数组下标从0开始,所以第i个物品的重量是wi-1

2、j对应表格的列(当前的背包容量)。

3、dpij=Math.max(...)就是我们在表格里写下的那个"取最大值"的动作。

动态规划和贪心算法对比
对比维度 贪心算法 (Greedy) 动态规划 (DP)
核心思想 活在当下,只看眼前(局部最优) 统筹全局,步步为营(全局最优)
决策方式 做出选择后绝不后悔(无回溯) 会考察所有可能的子问题,择优保留
是否记笔记 不需要,只记录当前状态 必须记(通过表格/备忘录避免重复计算)
能否保证最优 不一定(取决于问题是否满足贪心性质) 一定能(只要状态转移正确)
运行效率 极高(通常只需排序或单次扫描) 相对较低(通常需要填表,遍历所有子问题)
空间消耗 极低(通常只需几个变量) 较高(需要额外的内存存储 DP 表格)
适用条件 贪心选择性质 + 最优子结构 重叠子问题 + 最优子结构 + 无后效性
通俗比喻 凭直觉走迷宫,选最顺眼的方向,绝不回头 走迷宫时记下每个路口的最优路线,稳扎稳打

分治法

分治法和归并排序经常划到一起。

分治法是核心思想,归并排序是其中一种具体的算法。

相关推荐
hansang_IR1 小时前
【题解】P4456 [CQOI2018] 交错序列(数学递推)
c++·算法
青少儿编程课堂1 小时前
贪心算法进阶:区间调度与最少资源整合解析
c++·python·算法·贪心·信息学竞赛·区间调度
青山木1 小时前
Hot 100 --- 划分字母区间
java·数据结构·算法·leetcode·贪心算法
Sunsets_Red2 小时前
浅谈扫描线
c++·算法·编程·题解·洛谷·扫描线·信息学竞赛
a187927218312 小时前
【算法】双指针与滑动窗口(一):框架总纲——三类问题、一个原理与判决书
算法·leetcode·区间·双指针·滑动窗口·原理·算法讲解
shehuiyuelaiyuehao2 小时前
算法42,模拟算法,模拟z字形变换
算法
朝朝辞暮i2 小时前
C++第一课
开发语言·c++·算法
橘子汽水1682 小时前
Leetcode 208,207实现Trie前缀树,课程表
java·数据结构·算法·leetcode
hanlin032 小时前
刷题笔记:力扣第169题-多数元素
笔记·算法·leetcode