当前位置: 首页 > news >正文

天津建设委员会网站上查询系统电脑编程培训学校哪家好

天津建设委员会网站上查询系统,电脑编程培训学校哪家好,音乐网站制作源代码,查询域名备案来源0x3f:https://space.bilibili.com/206214 三叶姐的对背包问题的总结:【宫水三叶】详解完全背包一维空间优化推导(附背包问题攻略)https://leetcode.cn/circle/discuss/GWpXCM/ 文章目录0-1背包、完全背包及其拓展(…

来源0x3f:https://space.bilibili.com/206214

三叶姐的对背包问题的总结:【宫水三叶】详解完全背包一维空间优化推导(附背包问题攻略)https://leetcode.cn/circle/discuss/GWpXCM/

文章目录

  • 0-1背包、完全背包及其拓展(选/不选思想的代表)
    • 0-1背包常见变形【至多/恰好/至少】 :※重要
      • 纯0-1背包问题
      • [494. 目标和](https://leetcode.cn/problems/target-sum/)
        • 记忆化搜索
        • 1:1翻译成递推(动态规划)
        • 空间优化:滚动数组
        • 空间优化(一个数组)从后往前遍历背包
    • 完全背包变形
      • 纯完全背包问题
      • [322. 零钱兑换](https://leetcode.cn/problems/coin-change/)
        • 记忆化搜索
        • 翻译成递推
        • 空间优化(一维数组)从前到后遍历背包
    • 练习
      • [416. 分割等和子集](https://leetcode.cn/problems/partition-equal-subset-sum/)
      • [279. 完全平方数](https://leetcode.cn/problems/perfect-squares/)
      • [518. 零钱兑换 II](https://leetcode.cn/problems/coin-change-ii/)

对边界条件的总结:

不同的题目,所要的答案不同, 比如:方案数,最大、小值,数字个数,能否构成?

这也就意味着 dp 数组值可以为数值,也可以是 boolean 类型

另外,同样是数值的情况下,不同的要求,也会造成不同的初始值 f【0】【0】:

  • 能否构成: f【0】【0】 = True ; 0 可以构成 0

  • 方案数: f【0】【0】 = 1 ; 0 组成 0 只有一种方案

  • 数字个数: f【0】【0】 = 0 ; 0 组成 0 没有使用数字

  • 最大、小值: 问题一般会回归到 方案数 或 数字个数问题, 一般会使用到 max/min 函数约束答案,而且会使用 ±inf 初始化来表示极端情况。 比如:力扣 279 求最小数量(f【0】【j】 的初始值也是要考虑的)


0-1背包、完全背包及其拓展(选/不选思想的代表)

0-1背包常见变形【至多/恰好/至少】 :※重要

1、至多装capacity,求方案数/最大价值和

2、恰好装capacity,求方案数/最大/最小价值和

3、至少装capacity,求方案数/最小价值和

纯0-1背包问题

0-1背包问题:有N件物品和一个容量为C的背包。第i件物品的费用是v[i],价值是w[i]

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

dp[N][C+1]解法

import java.util.Scanner;
public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int C = sc.nextInt(); int[] v = new int[N]; int[] w = new int[N]; for (int i = 0; i < N; i++){ v[i] = sc.nextInt(); w[i] = sc.nextInt(); }System.out.println(maxValue(N, C, v, w)); }private static int maxValue(int N, int C, int[] v, int[] w) {int[][] dp = new int[N][C + 1];dp[0][0] = 0;//填充第 0 位物品在 0-C 容量下的初始值for (int i = 0; i < C + 1; i++) {dp[0][i] = i >= v[0] ? w[0] : 0;}// 先遍历物品 再遍历背包for (int i = 1; i < N; i++) {for (int j = 0; j < C + 1; j++) {int n = dp[i - 1][j]; // 不选该物品int y = 0;if (j >= v[i]) {y = w[i] + dp[i - 1][j - v[i]]; // 选择该物品}dp[i][j] = Math.max(n, y);}}return dp[N - 1][C];}
}

dp[2][C+1]解法

private static int maxValue(int N, int C, int[] v, int[] w) {int[][] dp = new int[2][C + 1];dp[0][0] = 0;for (int i = 0; i < C + 1; i++) {dp[0][i] = i >= v[0] ? w[0] : 0;}for (int i = 1; i < N; i++) {for (int j = 0; j < C + 1; j++) {int n = dp[(i - 1)%2][j]; // 不选该物品int y = 0;if (j >= v[i]) {y = w[i] + dp[(i - 1)%2][j - v[i]]; // 选择该物品}dp[i%2][j] = Math.max(n, y);}}return dp[(N - 1)%2][C];}

dp[C+1]解法

private static int maxValue(int N, int C, int[] v, int[] w) {int[] dp = new int[C + 1];for (int i = 0; i < C + 1; i++) {dp[i] = i >= v[0] ? w[0] : 0;}for (int i = 1; i < N; i++) {for (int j = C; j >= 0; j--) {int n = dp[j]; // 不选该物品int y = 0;if (j >= v[i]) {y = w[i] + dp[j - v[i]]; // 选择该物品}dp[j] = Math.max(n, y);}}return dp[C];}	

494. 目标和

难度中等1515

给你一个整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3 。
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3

示例 2:

输入:nums = [1], target = 1
输出:1

提示:

  • 1 <= nums.length <= 20
  • 0 <= nums[i] <= 1000
  • 0 <= sum(nums[i]) <= 1000
  • -1000 <= target <= 1000

从什么都不知道的题目到0-1背包问题的推理过程:

设添加+号的数和为p

则添加 - 号的数和为 sum-p

则 p-(sum-p) = target

==> p = (s+t)/2 => 在nums中选择一些数字,使得和恰好为p

记忆化搜索

class Solution {int[] nums;int[][] cache;public int findTargetSumWays(int[] nums, int target) {for(int x : nums) target += x;if(target < 0 || target % 2 == 1) return 0;target /= 2;this.nums = nums;int n = nums.length;cache = new int[n][target+1];for (int i = 0; i < n; i++)Arrays.fill(cache[i], -1); // -1 表示没用访问过return dfs(n - 1, target);}public int dfs(int i, int c){if(i < 0) return c == 0 ? 1 : 0;if(cache[i][c] != -1) return cache[i][c];int res = 0;if(c < nums[i]) {res = dfs(i-1, c); // 没有容量装下i位置的物体了}else{res = dfs(i-1, c) + dfs(i-1, c - nums[i]);}cache[i][c] = res;return res;}
}

1:1翻译成递推(动态规划)

class Solution {int[] nums;int[][] cache;public int findTargetSumWays(int[] nums, int target) {for(int x : nums) target += x;if(target < 0 || target % 2 == 1) return 0;target /= 2;int n = nums.length;int[][] f = new int[n+1][target+1];f[0][0] = 1; // 容量未0,所有数都选了for(int i = 0; i < n; i++){for(int c = 0; c <= target; c++){if(c < nums[i]){f[i+1][c] = f[i][c];}else{f[i+1][c] = f[i][c] + f[i][c-nums[i]];}}}return f[n][target];}// public int dfs(int i, int c){//     if(i < 0) return c == 0 ? 1 : 0;//     if(cache[i][c] != -1) return cache[i][c];//     int res = 0;//     if(c < nums[i]) {//         res = dfs(i-1, c); // 没有容量装下i位置的物体了//     }else{//         res = dfs(i-1, c) + dfs(i-1, c - nums[i]);//     }//     cache[i][c] = res;//     return res;// }
}

空间优化:滚动数组

(i+1) ==> (i+1) % 2

class Solution {int[] nums;int[][] cache;public int findTargetSumWays(int[] nums, int target) {for(int x : nums) target += x;if(target < 0 || target % 2 == 1) return 0;target /= 2;int n = nums.length;int[][] f = new int[2][target+1];f[0][0] = 1; // 容量未0,所有数都选了for(int i = 0; i < n; i++){for(int c = 0; c <= target; c++){if(c < nums[i]){f[(i+1) % 2][c] = f[i % 2][c];}else{f[(i+1) % 2][c] = f[i % 2][c] + f[i % 2][c-nums[i]];}}}return f[n % 2][target];}
}

空间优化(一个数组)从后往前遍历背包

从后往前遍历容量c

class Solution {int[] nums;int[][] cache;public int findTargetSumWays(int[] nums, int target) {for(int x : nums) target += x;if(target < 0 || target % 2 == 1) return 0;target /= 2;int n = nums.length;int[] f = new int[target+1];f[0] = 1; // 容量未0,所有数都选了for(int i = 0; i < n; i++){for(int c = target; c >= nums[i]; c--){f[c] = f[c] + f[c-nums[i]];}}return f[target];}
}

完全背包变形

纯完全背包问题

完全背包问题 : 有 N 种物品和一个容量为 C 的背包,每种物品都有无限件。

i 件物品的体积是 v[i],价值是 w[i]

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

其实就是在 0-1 背包问题的基础上,增加了每件物品可以选择多次的特点(在容量允许的情况下)

import java.util.Scanner;
public class Main{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); int N = sc.nextInt(); int C = sc.nextInt(); int[] v = new int[N]; int[] w = new int[N]; for (int i = 0; i < N; i++){ v[i] = sc.nextInt(); w[i] = sc.nextInt(); }System.out.println(maxValue(N, C, v, w)); }private static int maxValue(int N, int C, int[] v, int[] w) {int[] dp = new int[C + 1];//先遍历物品,再遍历背包for (int i = 0; i < N; i++) {for (int j = C; j >= v[i]; j--) {//比较格子的数量等于最多可选第i件物品多少次for (int k = 0 ;; k++) {if (j < v[i] * k) {break;}dp[j] = Math.max(dp[j], dp[j - v[i] * k] + w[i] * k);}}}return dp[C];}
}

完全背包的dp[C+1]解法

    private static int maxValue(int N, int C, int[] v, int[] w) {int[] dp = new int[C + 1];for (int i = 0; i < N; i++) {// for (int j = C; j >= v[i]; j--) { // 0-1 背包问题for (int j = v[i]; j <= C; j++) { // 完全背包问题int n = dp[j]; // 不选该物品int y = w[i] + dp[j - v[i]]; // 选择该物品dp[j] = Math.max(n, y);}}return dp[C];}
}

322. 零钱兑换

难度中等2307

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 231 - 1
  • 0 <= amount <= 104

记忆化搜索

class Solution {private int[] coins;private int[][] cache;public int coinChange(int[] coins, int amount) {this.coins = coins;int n = coins.length;cache = new int[n][amount + 1];for (int i = 0; i < n; i++)Arrays.fill(cache[i], -1); // -1 表示没用访问过int ans = dfs(n - 1, amount);return ans < Integer.MAX_VALUE / 2 ? ans : -1;}private int dfs(int i, int c) {// 当 c==0 时,表示这是一个合法的方案if (i < 0) return c == 0 ? 0 : Integer.MAX_VALUE / 2; // 除 2 是防止下面 + 1 溢出if (cache[i][c] != -1) return cache[i][c];if (c < coins[i]) return cache[i][c] = dfs(i - 1, c);return cache[i][c] = Math.min(dfs(i - 1, c), dfs(i, c - coins[i]) + 1);}
}

翻译成递推

class Solution {public int coinChange(int[] coins, int amount) {int n = coins.length;int[][] f = new int[n + 1][amount + 1];Arrays.fill(f[0], Integer.MAX_VALUE / 2); // 除 2 是防止下面 + 1 溢出f[0][0] = 0;for (int i = 0; i < n; ++i)for (int c = 0; c <= amount; ++c)if (c < coins[i]) f[i + 1][c] = f[i][c];else f[i + 1][c] = Math.min(f[i][c], f[i + 1][c - coins[i]] + 1);int ans = f[n][amount];return ans < Integer.MAX_VALUE / 2 ? ans : -1;}
}

空间优化(一维数组)从前到后遍历背包

class Solution {public int coinChange(int[] coins, int amount) {int[] f = new int[amount + 1];Arrays.fill(f, Integer.MAX_VALUE / 2); // 除 2 是防止下面 + 1 溢出f[0] = 0;for (int x : coins)for (int c = x; c <= amount; ++c)f[c] = Math.min(f[c], f[c - x] + 1);int ans = f[amount];return ans < Integer.MAX_VALUE / 2 ? ans : -1;}
}

练习

416. 分割等和子集

难度中等1645

给你一个 只包含正整数非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

提示:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 100
class Solution {// 每个元素只可以取一次,元素的价值和大小就是自己本身public boolean canPartition(int[] nums) {Arrays.sort(nums);int sum = 0;for(int num : nums) sum += num;if(sum % 2 != 0) return false;int target = sum / 2; // 背包为target时,有没有价值和为target(价值和只可能 <= target)int[] dp = new int[target+1]; // 空间优化:一个数组for(int i = 0; i < nums.length; i++){for(int j = target; j >= nums[i]; j--){dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);}}return dp[target] == target ? true : false;}
}

279. 完全平方数

难度中等1619

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,14916 都是完全平方数,而 311 不是。

示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4

示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

提示:

  • 1 <= n <= 104

朴素完全背包解法

class Solution {private static final int INF = Integer.MAX_VALUE / 2;public int numSquares(int n) {// 将可能用到的【物品】预处理出来List<Integer> list = new ArrayList<>();for(int i = 1; i * i <= n; i++) list.add(i*i);// 问题就变成了:给定数字中,每个数字可以使用无限次,求凑出目标值n所需要的最少数字个数是多少int[][] dp = new int[list.size()+1][n+1]; // 前i个数字中,凑出数字总和j所需要的最少数字个数//当没有任何数时,除了 f[0][0] 为 0(花费 0 个数值凑出 0),其他均为无效值Arrays.fill(dp[0], INF);  dp[0][0] = 0;// dp[i][j] = min(dp[i-1][j-k*t]+k) 0 <= k*t <= j; k:选k个数字i,第i个数字数值为tfor(int i = 1; i <= list.size(); i++){int x = list.get(i-1);for(int j = 0; j <= n; j++){// 对于不选第 i 个数的情况dp[i][j] = dp[i-1][j];// 对于选 k 次第 i 个数的情况for(int k = 1; k * x <= j; k++){// 能够选择 k 个 x 的前提是剩余的数字 j - k * x 也能被凑出if(dp[i-1][j-k*x] != INF){dp[i][j] = Math.min(dp[i][j], dp[i-1][j-k*x] + k);}}}}return dp[list.size()][n];}
}

空间优化:

class Solution {private static final int INF = Integer.MAX_VALUE / 2;public int numSquares(int n) {// 将可能用到的【物品】预处理出来List<Integer> list = new ArrayList<>();for(int i = 1; i * i <= n; i++) list.add(i*i);// 问题就变成了:给定数字中,每个数字可以使用无限次,求凑出目标值n所需要的最少数字个数是多少int[] dp = new int[n+1]; // 前i个数字中,凑出数字总和j所需要的最少数字个数//当没有任何数时,除了 f[0][0] 为 0(花费 0 个数值凑出 0),其他均为无效值Arrays.fill(dp, INF);  dp[0] = 0;// dp[i][j] = min(dp[i-1][j-k*t]+k) 0 <= k*t <= j; k:选k个数字i,第i个数字数值为tfor(int i = 1; i <= list.size(); i++){int x = list.get(i-1);for(int j = x; j <= n; j++){dp[j] = Math.min(dp[j], dp[j-x] + 1);}}return dp[n];}
}

518. 零钱兑换 II

难度中等1005

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0

假设每一种面额的硬币有无限个。

题目数据保证结果符合 32 位带符号整数。

示例 1:

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例 2:

输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3 。

示例 3:

输入:amount = 10, coins = [10] 
输出:1

提示:

  • 1 <= coins.length <= 300
  • 1 <= coins[i] <= 5000
  • coins 中的所有值 互不相同
  • 0 <= amount <= 5000
class Solution {public int change(int amount, int[] coins) {int[] dp = new int[amount+1];dp[0] = 1;for(int x : coins){for(int j = x; j <= amount; j++){dp[j] = dp[j] + dp[j-x];}}return dp[amount];}
}
http://www.dt0577.cn/news/8148.html

相关文章:

  • 营销型网站单页面手机网站制作教程
  • 装修公司网站平台网站建设与管理属于什么专业
  • 在手机上创建网站网络搜索引擎
  • vip视频解析网站怎么做的如何在百度上推广业务
  • 兴化建设局网站查关键词
  • 淮南网站制作如何让新网站被收录
  • 泰格豪雅手表官方网站百度引擎搜索入口
  • 网站托管流程深圳网络营销模式
  • 人社局网站建设方案怎么注册一个自己的网址
  • 已注册商标查询官网百度seo怎么优化
  • 台州铭企做的网站如何发布视频赚钱
  • 做网站代理成都网站建设seo
  • 专业做网站的软件怎么做网址
  • 视觉营销网站app推广注册放单平台
  • 谈谈网站开发流程企业查询系统
  • 以3d全景做的网站越秀seo搜索引擎优化
  • 做网站被骗该咋样做域名注册流程和费用
  • 什么是网络营销网络营销的特点有哪些淘宝关键词优化技巧
  • 东莞做网站推广百度客户端官网
  • 政府网站平台日常制度建设百度新站关键词排名
  • 用Axure做的原型网站百度云百度搜首页
  • 做推广网站的文章seo全网营销公司
  • ps做图哪个网站好杭州网站seo优化
  • 自己免费做网站的流程知乎推广优化
  • 怎么样能够为一个网站做推广济南搜索引擎优化网站
  • 大连网站排名网络推广公司做外贸网站的公司
  • 可以免费做试卷题目的网站杭州市优化服务
  • 扬中市做网站广点通推广登录入口
  • 免费稳定网站空间seo网站收录工具
  • 怎么做网站推广林芝地区北京百度推广公司