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

贪心算法

动态规划

小偷背包示例

knapsack是背包的意思。

代码:

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个物品的重量是w[i-1]。
2、j对应表格的列(当前的背包容量)。
3、dp[i][j]=Math.max(…)就是我们在表格里写下的那个“取最大值”的动作。

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

分治法

分治法和归并排序经常划到一起。
分治法是核心思想,归并排序是其中一种具体的算法。

更多推荐