Day38--動態規劃--322. 零錢兌換,279. 完全平方數,139. 單詞拆分,56. 攜帶礦石資源(卡碼網),背包問題總結

Day38–動態規劃–322. 零錢兌換,279. 完全平方數,139. 單詞拆分,56. 攜帶礦石資源(卡碼網),背包問題總結

今天的是幾道經典的“完全背包”題目。前兩道題目,要區分求的是“價值”,還是“達成價值的最大/最小數量“。最后一道題目,介紹了多重背包,其實是可以轉為01背包去做。

322. 零錢兌換

思路:

  1. 確定dp含義:dp[j]:湊足總額為j所需錢幣的最少個數為dp[j]

  2. 湊足總額為j - coins[i]的最少個數為dp[j - coins[i]],那么只需要加上一個錢幣coins[i]dp[j - coins[i]] + 1就是dp[j]

    然后dp[j] 要取所有 dp[j - coins[i]] + 1 中最小的。

    遞推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

  3. dp[0] = 0;

  4. 遍歷順序:都可以,因為求的不是排列數或者組合數。

class Solution {public int coinChange(int[] coins, int amount) {// 最大值,因為要用到Math.minint max = Integer.MAX_VALUE;int n = coins.length;// bagSize 是 amountint[] dp = new int[amount + 1];// 初始化Arrays.fill(dp, max);dp[0] = 0;// 動態規劃for (int i = 0; i < n; i++) {// 多重背包,要正序for (int j = coins[i]; j <= amount; j++) {// 不等于max,才證明是由硬幣組成的if (dp[j - coins[i]] != max) {// 等式左邊的dp[j],是更新后的,是這一層的// 等式右邊的dp[j],是更新前的,是上一層的// 等式右邊的dp[j - coins[i]],在dp[j]的左邊,所以是同一層的,已經更新過的// 對于`dp[j - coins[i]] + 1`這個因素,它的意思是,騰出coins[i]的空間之后,在本層找[j - coins[i]]這個位置是需要多少硬幣的,+1(加上當前遍歷的這枚coins[i])就是當前位置的硬幣數了dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);}}// // 打印觀察// for (int k = 0; k <= amount; k++) {//     System.out.print(dp[k]+" ");// }// System.out.println(" ");}return dp[amount] == max ? -1 : dp[amount];}
}

簡潔版:

class Solution {public int coinChange(int[] coins, int amount) {int max = Integer.MAX_VALUE;int n = coins.length;int[] dp = new int[amount + 1];Arrays.fill(dp, max);dp[0] = 0;for (int i = 0; i < n; i++) {for (int j = coins[i]; j <= amount; j++) {if (dp[j - coins[i]] != max) {dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);}}}return dp[amount] == max ? -1 : dp[amount];}
}

279. 完全平方數

思路:

  1. 確定dp數組含義:dp[j]就是和為 j 的完全平方數的最少數量 。
  2. 遞推公式:dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
    • 情況一:就是等于上一層。
    • 情況二如果要等于這一層的話,先取:減去當前的數字i的平方那個位置的數量,然后加i這“一位”數,所以+1
    • 然后情況一、二取最小值。
  3. 初始化:
    • dp[0] 是無意義的,因為沒有數的平方等于0。但是初始化需要dp[0] = 0;
    • 因為有了Math.min(),所以非0下標的地方要全部賦值max
  4. 遍歷順序:只要數量,那就求排列數或者組合數都可以。那就是先背包再數字,或者先數字再背包都可以。
  5. 額外的剪枝優化:可以減少遍歷數量。要平方得到n,最少只需要一個根號n,所以遍歷到的最大值設為√n就好。
// bagSize 是 n
// nums[] 的上限是 Math.sqrt(n);
class Solution {public int numSquares(int n) {// 需要用到Math.minint max = Integer.MAX_VALUE;// 剪枝,可以減少遍歷數量。要平方得到n,最少只需要一個根號nint numsMax = (int) Math.sqrt(n);// 一維dp數組int[] dp = new int[n + 1];// 初始化Arrays.fill(dp, max);// dp[0] 是無意義的,因為沒有數的平方等于0。但是初始化需要,不然是max的話,做不了了dp[0] = 0;// i從1開始for (int i = 1; i <= numsMax; i++) {// j直接從i方開始遍歷,因為小于i方的數,本層都更新不了,等于上層數據for (int j = i * i; j <= n; j++) {// 肯定要min的,比如n=16,直接是1個4方就夠了,而不是4個2方// 為什么是+1?遍歷到了數值i了,這一層先騰空i*i的空間,再往前找dp[j - i * i]的數量,加上i這個數(這一個數),所以就是加1dp[j] = Math.min(dp[j], dp[j - i * i] + 1);}}return dp[n];}
}

139. 單詞拆分

思路:

  1. dp數組含義:字符串長度為i的話,dp[i]為true,表示可以拆分為一個或多個在字典中出現的單詞。
  2. 遞推公式:
    • 如果這個區間是存在于字典里的一個串,這個串的開頭,跟已經判斷過的內容的結尾是相接的。那么這個串的末尾+1的位置給它賦值為true。
    • 如果確定dp[j] 是true(到j這里都是true),且 [j, i] 這個區間的子串出現在字典里,那么dp[i]一定是true。(j < i )。
    • 所以遞推公式是 if([j, i] 這個區間的子串出現在字典里 && dp[j]是true) 那么 dp[i] = true
  3. 初始化:dp[0] = true;
  4. 遍歷順序:因為字典中的單詞,可能會被重復取,所以要按照排列數的方法來做——即先遍歷背包,再遍歷物品。
class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> wordSet = new HashSet<>(wordDict);boolean[] dp = new boolean[s.length() + 1];dp[0] = true;for (int i = 1; i <= s.length(); i++) { // 遍歷背包for (int j = 0; j < i; j++) { // 遍歷物品String word = s.substring(j, i); //substring(起始位置,結束位置)if (wordSet.contains(word) && dp[j]) {dp[i] = true;}}}return dp[s.length()];}
}

思路:

上面的思路,是不斷截取子字符串,判斷是否在字典中。

還可以這樣做,i往前走,遍歷字典里面的所有單詞,判斷[i - len, i)這個區間的字符串是否跟字典里某個單詞相等,是的話,當前位置設為true。(注意substring方法是左閉右開,當前i的位置已經是下一個單詞的開頭了。所以剛好在索引s.length()的時候,可以返回最終結果)

class Solution {public boolean wordBreak(String s, List<String> wordDict) {boolean[] dp = new boolean[s.length() + 1];dp[0] = true;for (int i = 1; i <= s.length(); i++) {for (String word : wordDict) {int len = word.length();if (i >= len && dp[i - len] && word.equals(s.substring(i - len, i))) {dp[i] = true;break;}}}return dp[s.length()];}
}

記錄:這道題感覺跟常規的背包問題,忽然間不太熟悉,想了許久沒出來,直接看題解,理解題目,下次二刷。

56. 攜帶礦石資源(卡碼網)

這道題目是用來理解多重背包問題的。

多重背包的樣子:

重量價值數量
物品01152
物品13203
物品24302

實際上,換個角度就變成01背包了:

重量價值數量
物品01151
物品01151
物品13201
物品13201
物品13201
物品24301
物品24301

思路:

所以就是多套一層循環,把物品i遍歷對應的次數就行了。按照常規01背包的步驟來做。

import java.util.*;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 背包容量int bagSize = in.nextInt();// 一共有n種礦石int n = in.nextInt();// 每種礦石的重量int[] weight = new int[n];// 每種礦石的價值int[] value = new int[n];// 每種礦石分別有多少塊int[] perAmount = new int[n];// 輸入for (int i = 0; i < n; i++) {weight[i] = in.nextInt();}for (int i = 0; i < n; i++) {value[i] = in.nextInt();}for (int i = 0; i < n; i++) {perAmount[i] = in.nextInt();}// dp數組的含義:在bagSize的容量下,最大能取到的總價值int[] dp = new int[bagSize + 1];//動態規劃// 遍歷每種礦石for (int i = 0; i < n; i++) {// 遍歷每種礦石的數量for (int per = 0; per < perAmount[i]; per++) {// 遍歷背包容量for (int j = bagSize; j >= weight[i]; j--) {// 常規的01背包的遞推公式dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);}}}// 輸出結果System.out.println(dp[bagSize]);}
}

背包問題總結

最關鍵的兩步:遞推公式 + 遍歷順序

遞推公式:

  • 按價值
    • 最多能裝多少?
    • 能否裝滿?
    • 遞推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  • 求有多少種方法?
    • 組合數
    • 排列數
    • 遞推公式:dp[j] += dp[j - nums[i]]
  • 裝滿背包時候的最小個數
    • 題目:零錢兌換、完全平方數
    • 遞推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

遍歷順序:

  • 01背包:倒序(因為要左上方和正上方的數據)
  • 完全背包:正序(因為要左方和正上方的數據)
    • 求組合數:先物品,后背包
    • 求排列數:先背包,后物品
    • 求最大數、最小數:無所謂

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/92610.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/92610.shtml
英文地址,請注明出處:http://en.pswp.cn/web/92610.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

應用層Http協議(1)

應用層Http協議&#xff08;1&#xff09; 在互聯網世界中&#xff0c;HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是一個至關重要的協議。它定義了客戶端&#xff08;如瀏覽器&#xff09;與服務器之間如何通信&#xff0c;以交換或傳…

elementui input無法輸入問題

背景。開發小程序。自定義表單在pc段設置好input輸入框屬性后。 在小程序端無法輸入原因&#xff1a;長度受限制&#xff0c;導致input組件的maxlength屬性認為長度是0導致無法輸入任何值。看解釋是應為遇到空字符串等情況會設置為0解決。因為未找到設置maxlength為0處&#xf…

算法_python_學習記錄_02

算法學習和視頻學習過程中&#xff0c;有許多前幾天還不知道的知識點&#xff0c;現在一點一點歸納整理出來&#xff0c;穩步前進&#xff0c;前進~ 20_貪心算法系列題 00_參考文檔 詳解貪心算法&#xff08;Python實現貪心算法典型例題&#xff09;_順序貪婪算法-CSDN博客P…

Meta AI水印計劃的致命缺陷——IEEE Spectrum深度文獻精讀

一、原文信息 標題: Metas AI Watermarking Plan Is Flimsy, at Best 中文譯名: Meta的AI水印計劃脆弱不堪 作者: David Evan Harris(加州大學伯克利分校)、Lawrence Norden(紐約大學法學院) 發表日期: 2024年3月5日 發表期刊: IEEE Spectrum 二、原文全文翻譯 Met…

gpt-oss 全量技術解讀

一、概述 gpt-oss 是 OpenAI 發布的開放權重&#xff08;open-weight&#xff09;模型系列&#xff0c;面向強推理、Agent 能力與多樣化應用場景。 提供兩種規格&#xff1a; gpt-oss-120b&#xff1a;面向生產與高推理需求&#xff0c;單卡 80GB GPU&#xff08;如 NVIDIA …

實現EtherNet/IP網絡與Modbus TCP網絡之間數據互通

硬件連接與配置使用工業以太網網關&#xff08;如ENE-350&#xff09;作為橋接設備&#xff0c;通過以太網交換機實現硬件互聯。 網關需根據應用場景配置為EtherNet/IP從站或Modbus TCP主/從站模式。案例1&#xff1a;EtherNet IP主站PLC和Modbus TCP主站PLC的互聯網關配置&…

zookeeper因jute.maxbuffer啟動異常問題排查處理

#作者&#xff1a;程宏斌 文章目錄一、前言二、問題描述三、定位過程四、問題根因五、解決方案根本解決方案應急處理方案調大參數可能出現的問題六、總結為什么超出會報錯官方對于jute.maxbuffer的解釋注意事項官方建議一、前言 在分布式系統中&#xff0c;ZooKeeper作為關鍵的…

Java基礎十三: List

目錄 1.Java LinkedList 的高級應用與示例 1.1 LinkedList的基本使用 基本操作示例 1.2 LinkedList獨有的方法 特定方法示例 1.3 隊列模式&#xff08;先進先出&#xff09; 隊列模式示例 1.4 棧模式&#xff08;先進后出&#xff09; 棧模式示例 總結 2.Java Vecto…

[機器學習]03-基于核密度估計(KDE)的鳶尾花數據集分類

關鍵點&#xff1a;使用核密度估計&#xff08;KDE&#xff09; 估計類別條件概率密度&#xff08;高斯核&#xff0c;帶寬0.2&#xff09;采用最大后驗概率&#xff08;MAP&#xff09; 決策準則進行分類程序代碼&#xff1a;import random import matplotlib from sklearn.ne…

jmeter怎么實現多個請求真正的同時發送

1.首先在插件管理器Plugins Manager中搜索插件Parallel Controller&Sampler&#xff0c;勾選上對應的插件后&#xff0c;在右下角點擊Apply Changes and Restart JMeter&#xff0c;安裝插件2.插件安裝完畢后&#xff0c;然后在線程組上面右擊&#xff0c;點擊添加--邏輯控…

復雜環境下車牌識別準確率↑29%:陌訊動態特征融合算法實戰解析

原創聲明本文為原創技術解析&#xff0c;核心技術參數與架構設計引用自《陌訊技術白皮書》&#xff0c;轉載需注明來源。一、行業痛點&#xff1a;車牌識別的現實挑戰在智慧交通、停車場管理等場景中&#xff0c;車牌識別作為關鍵技術環節&#xff0c;長期面臨多重環境干擾。據…

Express中間件和路由及響應方法

1.中間件分類 應用程序級別中間件 通過 app.use() 或 app.METHOD()&#xff08;如 app.get&#xff09;綁定的中間件&#xff0c;作用于整個應用程序。例如 記錄請求日志、解析請求體等全局功能。例如&#xff1a; app.use((req, res, next) > {console.log(Request URL:…

Dokcer創建中間件環境

簡而言之&#xff0c;用docker來搞中間件環境比價好使&#xff0c;不用關心各種環境了 rabbitmqsudo docker run -d \--name rabbitmq \-p 5672:5672 \-p 15672:15672 \rabbitmq:3.8-managementredis 5.0.3 docker start my-redisdocker run --name my-redis -d -p 6379:6379 \…

Linux高級編程-文件操作

1.Linux下的文件類型7種文件類型&#xff1a;b 塊設備文件 -------> 存儲類設備&#xff08;硬盤&#xff09; c 字符設備文件 ------->如輸入輸出設備&#xff08;鼠標鍵盤顯示器...&#xff09; d 目錄文件 ------->文件夾 - 普通文件 -------&g…

web:vue中import *** from 和import {***} from的區別

在Vue.js中,import語句用于導入模塊、組件或變量等。使用帶花括號{}和不帶花括號的區別主要在于導入的內容是具名導出(named exports)還是默認導出(default export)。 默認導入 (Default Import) - 不帶花括號 import Vue from vue; import MyComponent from ./MyCompone…

Mysql如何優化my.conf配置文件?

優化 MySQL 的 my.cnf 配置文件&#xff0c;可以顯著提升數據庫性能&#xff0c;特別是在高并發或大數據量場景下。以下是優化 my.cnf 的方法和建議&#xff0c;涵蓋 常見配置項、參數說明 和 優化技巧。1. 優化前的準備工作在修改 my.cnf 之前&#xff0c;需了解以下內容&…

Cherryusb UAC例程對接STM32內置ADC和DAC播放音樂和錄音(上)=>TIM+DAC+ADC+DMA正弦波回環測試

0. 概述 文本目標基于Cherryusb官方例程audio_v1_mic_speaker_multichan_template.c&#xff0c;底層對接STM32的內置ADC和DAC&#xff0c;實現錄音和播放。通過電腦播放歌曲&#xff0c;板子發出聲音。通過電腦錄音機開啟錄音&#xff0c;板子作為麥克風采集聲音&#xff0c;…

數模個人筆記

寫在前面&#xff1a;不建議觀看&#xff0c;會爛尾的1.馬氏鏈&#xff1a;狀態空間指的是隨機變量的取值范圍&#xff0c;xi稱為一個狀態&#xff0c;應用背景在現在的條件下下一狀態發生的概率&#xff0c;比如退火&#xff0c;他的條件概率可化簡為&#xff1a;且nm時刻的概…

Spring Boot自定義Starter:從原理到實戰全解析

1. 背景與需求1.1 什么是Starter&#xff1f; Spring Boot的起步依賴&#xff08;Starter&#xff09;是一種特殊的依賴描述符&#xff0c;用于簡化Spring應用的依賴管理和自動配置。官方文檔將Starter定義為“一組方便的依賴描述符”&#xff0c;開發者只需引入對應的Starter&…

安寶特方案丨工業AR+AI質檢方案:致力于提升檢測精度與流程效率

據IDC預測&#xff0c;2025年中國工業AI質檢市場規模將達62億元&#xff0c;年復合增長率28.5%&#xff0c;新能源、消費電子、高端裝備三大領域貢獻超70%市場份額。這一數據印證了AI質檢已從可選技術升級為制造業降本增效的生存剛需。當前制造業質檢環節正面臨&#xff1a;精度…