专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

搞定leetcode 01背包问题 [PHP]

定义dp[i][j]表示取前i个物品,在背包容量不超过j的情况下能得到的最大价值。
对于第i个物品,可以选择 或者不选择。

  • 如果不选择第i个物品放入背包,那么dp[i][j]其实就是等于dp[i-1][j],即只考虑前i-1个商品,不超过容量j所能得到的最大值。
  • 如果要选择放入第i个物品到背包,那么此时只要再考虑前i-1个商品,容量不超过j-weight[i-1]的时候能得到的最大值,即dp[i-1][j-weight[i-1]]. 因为第i个物品的容量是weight[i-1]。此时的最大值再加上物品i的价值即可。
  • 这里需要考虑j-weight[i-1]可能小于0,即当前物品i的容量已经大于背包容量了,此时的最大值是其上一个状态
  • 最后要求的就是
//n个物品,包容量w,每个物品的大小weight和价值value, 求不超过w 最大价值
    function knapsack($w, $n, $weight, $value) {
        $dp = array_fill(0, $n + 1, array_fill(0, $w + 1, 0));

        for ($i = 1; $i < $n; $i++) {
            for ($j = 1; $j <= $w; $j++) {
                if ($j >= $weight[$i-1]) {
                    //不放入第i个物品,放入第i个物品,取最大值
                    $dp[$i][$j] = max($dp[$i - 1][$j], $dp[$i - 1][$j - $weight[$i - 1]] + $value[$i-1]);
                } else {
                    $dp[$i][$j] = $dp[$i-1][$j];
                }
            }
        }

        return $dp[$n][$w];
    }

https://leetcode-cn.com/problems/partition-equal-subset-sum/
leetcode 416 分隔等和子集。

function canPartition($nums) {
        $sum = array_sum($nums);
        if ($sum % 2 == 1) {
            return false;
        }
        $sum = $sum / 2;
        $len_n = count($nums);
        $dp = array_fill(0, $len_n + 1, array_fill(0, $sum + 1, false));

        for ($i = 0; $i <= $len_n; $i++) {
            $dp[$i][0] = true;
        }

        //dp[i][j]表示 对于前i个物品,容量为j的情况下,要是能恰好装满包,则为true,否则为false
        for ($i = 1; $i <= $len_n; $i++) {
            for ($j = 1; $j <= $sum; $j++) {
                if ($j - $nums[$i-1] >= 0) {
                    //不选择第i个数字,表示只从前i-1个数里选,凑够容量j的情况,那么就跟上一个状态一样。   ||
                    //选择第i个数字的话, 只有看前i-1个数里能不能再选出j-weight[i-1]的情况就行。
                    $dp[$i][$j] = $dp[$i - 1][$j] || $dp[$i-1][$j - $nums[$i-1]];
                } else {
                    $dp[$i][$j] = $dp[$i-1][$j];
                }
            }
        }

        return $dp[$len_n][$sum];
    }

经过空间压缩后的。注意的是此时的j要从sum开始往小遍历,也就是从后往前填表。因为
$dp[$i][$j] = $dp[$i - 1][$j] || $dp[$i-1][$j - $nums[$i-1]];
上面这个状态转移方程表示当前i,j状态下的值与i-1状态有关。是上一行(次)的数据。
$dp[$j] = $dp[$j] || $dp[$j - $nums[$i-1]];
要还是从前往后遍历的话,上次的数据可能会被覆盖掉。
比如现在j=8,当前数字是4 那么dp[8]会和上次的dp[8]和上次的dp[4]有关,你要是从前开始遍历,上次存储的dp[4]的值就被这次的覆盖了,从而出错。而从后往前遍历则不会出现这种情况。当时我也是理解了好久没看明白。后来填了表,才看懂。下面的文章讲的也不错。

tech.souyunku.com/Christal-R/…

 function canPartition($nums) {
        $sum = array_sum($nums);
        if ($sum % 2 == 1) {
            return false;
        }
        $sum = $sum / 2;
        $len_n = count($nums);
        $dp = array_fill(0, $sum + 1, false);
        $dp[0] = true;

        for ($i = 1; $i <= $len_n; $i++) {
            for ($j = $sum; $j >= 1; $j--) {
                if ($j - $nums[$i-1] >= 0) {
                    $dp[$j] = $dp[$j] || $dp[$j - $nums[$i-1]];
                }
            }
        }

        return $dp[$sum];
    }

labuladong.gitbook.io/algo/dong-t…

tech.souyunku.com/Christal-R/…

文章永久链接:https://tech.souyunku.com/45138

未经允许不得转载:搜云库技术团队 » 搞定leetcode 01背包问题 [PHP]

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们