Leetcoder Day38| 動態規劃part05 背包問題

1049.最后一塊石頭的重量II

有一堆石頭,每塊石頭的重量都是正整數。

每一回合,從中選出任意兩塊石頭,然后將它們一起粉碎。假設石頭的重量分別為?x 和?y,且?x <= y。那么粉碎的可能結果如下:

如果?x == y,那么兩塊石頭都會被完全粉碎;

如果?x != y,那么重量為?x?的石頭將會完全粉碎,而重量為?y?的石頭新重量為?y-x。

最后,最多只會剩下一塊石頭。返回此石頭最小的可能重量。如果沒有石頭剩下,就返回 0。

示例:

  • 輸入:[2,7,4,1,8,1]
  • 輸出:1

解釋:

  • 組合 2 和 4,得到 2,所以數組轉化為 [2,7,1,8,1],
  • 組合 7 和 8,得到 1,所以數組轉化為 [2,1,1,1],
  • 組合 2 和 1,得到 1,所以數組轉化為 [1,1,1],
  • 組合 1 和 1,得到 0,所以數組轉化為 [1],這就是最優值。

提示:

  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 1000

本題要求最小的石頭重量,最好的情況就是最后剩下的兩個石頭重量一致,結果為0。那也就跟昨天的分割子集的本質一樣,將這個數組分割成兩個子集,使得兩個子集的元素和相等。因此看是否可以將石頭重量集合拆分為總和為sum/2的子集。因為本題石頭粉碎是不可逆的,因此屬于01背包問題,那么就開始對應如下四點:

  • 背包的可容納的重量為sum / 2
  • 背包要放入的石頭的重量也就是石頭的價值
  • 背包如果正好裝滿,說明找到了總和為 sum / 2 的子集。
  • 背包中每一個元素是不可重復放入

動規五部曲:

  1. 確定dp數組以及下標的含義:dp[j]表示重量為j的背包,最多可以背的重量為dp[j]
  2. 確定遞推公式:dp[j]=max(dp[j], dp[j-stones[i]]+stones[i])
  3. dp數組如何初始化:sum+=stones[i] target=sum/2
  4. 遞歸順序:先遍歷石頭,再遍歷重量,并且重量要倒序遍歷

如果背包需要滿足的容量為target,當dp[target]==target時,背包就裝滿了,也就是本題的結果為0。如果不能滿足,因為sum/2是向下取整,所以sum-dp[target]一定大于dp[target],所以相撞以后剩下的石頭重量為(sum-dp[target])-dp[target]

class Solution {public int lastStoneWeightII(int[] stones) {int sum=0;for(int i=0;i<stones.length;i++){sum+=stones[i];}int target=sum>>1;int[] dp= new int[target+1];for(int i=0;i<stones.length;i++){for(int j=target;j>=stones[i];j--){dp[j]=Math.max(dp[j], dp[j-stones[i]]+stones[i]);}}return (sum-dp[target])-dp[target]; }
}

注意:這里不需要再單獨判斷一下dp[target]是否等于target了,如果等于的話,其實最后相當于sum-2*target=0了,如果多寫了這一步判斷,反而會漏算情況。

并且sum/2的空間復雜度要比sum>>1,移位運算高,所以最好寫后者。

494.目標和

給定一個非負整數數組,a1, a2, ..., an, 和一個目標數,S。現在你有兩個符號?+?和?-。對于數組中的任意一個整數,你都可以從?+?或?-中選擇一個符號添加在前面。

返回可以使最終數組和為目標數 S 的所有添加符號的方法數。

示例:

  • 輸入:nums: [1, 1, 1, 1, 1], S: 3
  • 輸出:5

解釋:

  • -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

一共有5種方法讓最終目標和為3。

提示:

  • 數組非空,且長度不會超過 20 。
  • 初始的數組的和不會超過 1000 。
  • 保證返回的最終結果能被 32 位整數存下。

這道題先用動態規劃五部曲想了一下:本題依然是只能取一次,所以還是01背包思路

  1. 確定dp數組以及下標的含義:dp[j]表示達到和為j的值有dp[j]種方法
  2. 確定遞推公式:目前還不知道
  3. dp數組如何初始化:dp[0]=1,因為當只有1個元素的時候,那么就只有一種方法
  4. 確定遍歷順序:還是按照元素從前向后,按照數值從后向前
  5. 舉例推導dp數組:遞推公式還沒出來,暫時舉不出來例子

腦子比較累,直接看了題解:

本題要如何使表達式結果為target。首先因為有sum,所以left + right = sum,sum是固定的,因此right = sum - left。既然為target,那么就一定有? left組合 - right組合 = target,這里left就是加法的總和,right就是減法的總和,公式來了, left - (sum - left) = target 推導出 left = (target + sum)/2, target是固定的,sum是固定的,left就可以求出來。此時問題就是在集合nums中找出和為left的組合。此時問題就轉化為,裝滿容量為left的背包,有幾種方法。還要注意幾種特殊的情況:(target + sum) / 2 應該擔心計算的過程中向下取整有沒有影響,如果sum為5,target為2,那么無論怎樣也不會到達target值,也就是說當sum+target為奇數時,是沒有解決方案的。并且如果target的的絕對值大于sum,也是沒有解決方法的,直接返回0。

只要搞到nums[i],湊成dp[j]就有dp[j - nums[i]] 種方法。

例如:dp[j],j 為5,

  • 已經有一個1(nums[i]) 的話,有 dp[4]種方法 湊成 容量為5的背包。
  • 已經有一個2(nums[i]) 的話,有 dp[3]種方法 湊成 容量為5的背包。
  • 已經有一個3(nums[i]) 的話,有 dp[2]中方法 湊成 容量為5的背包
  • 已經有一個4(nums[i]) 的話,有 dp[1]中方法 湊成 容量為5的背包
  • 已經有一個5 (nums[i])的話,有 dp[0]中方法 湊成 容量為5的背包

那么湊整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起來。

所以求組合類問題的公式,都是類似這種:dp[j] += dp[j - nums[i]]

import java.lang.Math;
class Solution {public int findTargetSumWays(int[] nums, int target) {int sum=0;for(int i=0;i<nums.length;i++){sum+=nums[i];}int left=(sum+target)>>1;if((sum+target)%2==1) return 0;if(Math.abs(target)>sum) return 0;int[] dp= new int[left+1];dp[0]=1;for(int i=0;i<nums.length;i++){for(int j=left;j>=nums[i];j--){dp[j]+= dp[j-nums[i]];}}return dp[left];}
}

474.一和零

給你一個二進制字符串數組 strs 和兩個整數 m 和 n 。

請你找出并返回 strs 的最大子集的大小,該子集中 最多 有 m 個 0 和 n 個 1 。

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。

示例 1:

  • 輸入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3

  • 輸出:4

  • 解釋:最多有 5 個 0 和 3 個 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。 其他滿足題意但較小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不滿足題意,因為它含 4 個 1 ,大于 n 的值 3 。

示例 2:

  • 輸入:strs = ["10", "0", "1"], m = 1, n = 1
  • 輸出:2
  • 解釋:最大的子集是 {"0", "1"} ,所以答案是 2 。

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i]?僅由?'0' 和?'1' 組成
  • 1 <= m, n <= 100

本題還是一個背包問題,本題中strs 數組里的元素就是物品,每個物品都是一個,只能取一次,因此還是01背包問題。這里限制了兩個元素的大小,這兩個大小之間是沒有什么制約關系的,相當于有兩個背包,所以要定義一個二維dp數組dp[i][j]繼續開始動規五部曲:

  1. 確定dp數組以及下標的含義:dp[i][j]表示最多取i個1和j個0后的最大子集的大小
  2. 確定遞推公式:dp[i][j]是由前一個已經選好的子串推導而來,假設前面那個子串已經有zero個0和one個1,那么dp[i][j]=dp[i-zero][j-one]+1,并且還要跟自己做比較,取最大值。
  3. dp數組如何初始化:初始化為0
  4. 確定遍歷順序:遍歷物品要從前往后,遍歷背包要從后往前,這里m和n都是背包,所以都是從后往前遍歷。
  5. 舉例推導dp數組:以輸入:["10","0001","111001","1","0"],m = 3,n = 3為例,最后dp數組的狀態如下所示:
    ?

class Solution {public int findMaxForm(String[] strs, int m, int n) {int[][] dp = new int[m+1][n+1];for(String str:strs){int zero=0, one=0;for(char c : str.toCharArray()){if(c =='0') zero++;else one++;}for(int i=m;i>=zero;i--){for(int j=n;j>=one;j--){dp[i][j]=Math.max(dp[i][j], dp[i-zero][j-one]+1);}}}return dp[m][n];}
}

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

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

相關文章

012集—二維輕量多線段LWpolyline設置凸度bulge——vba實現

本文主要講LightweightPolyline ,即輕量多段線。 ObjectARX 中提供了三種多段線的相關類:AcDbPolyline&#xff08;對應vba中lightweightpolyline&#xff09; 、AcDb2dPolyline (對應vba中polyline)和 AcDb3dPolyline Polyline就是&#xff08;輕量&#xff09;多段線&…

藍牙BLE 5.0、5.1、5.2和5.3區別

隨著科技的不斷發展&#xff0c;藍牙技術也在不斷進步&#xff0c;其中藍牙BLE&#xff08;Bluetooth Low Energy&#xff09;是目前應用廣泛的一種藍牙技術&#xff0c;而BLE 5.0、5.1、5.2和5.3則是其不斷升級的版本。本文將對這四個版本的區別進行詳細的比較。 一、BLE 5.0…

未來趨勢:個人化資源整合將成為主流

隨著科技的發展和社會的進步&#xff0c;我們正步入一個高度個性化和數字化的時代&#xff0c;在這個時代中&#xff0c;資源的整合與分配模式正發生著深刻的變革。本文試圖論證&#xff0c;未來的資源整合將更傾向于個人化&#xff0c;即資源將以更加靈活、定制化的方式流向個…

【mysql技巧】如何在這個mysql語句執行前加個前提,也就是只有表里沒有相同數據才進行添加插入操作

文章目錄 我們正常的mysql插入數據語句加個前提完結 我們正常的mysql插入數據語句 INSERT INTO guild_nakadai.admin_role_permission (role_id, permission_id, type) VALUES ((SELECT id FROM guild_nakadai.admin_roles WHERE name"員工"),(SELECT id FROM guil…

Unity UGUI之Slider基本了解

在Unity中&#xff0c;Slider&#xff08;滑動條&#xff09;是一種常用的用戶界面控件之一&#xff0c;允許用戶通過拖動滑塊來選擇一個數值。常常應用于調節數值&#xff08;如調節音量、亮度、游戲難度等&#xff09;、設置選項等。 以下是Slider的基本信息和用法: 1、創建…

每日OJ題_斐波那契dp①_力扣1137. 第 N 個泰波那契數

目錄 動態規劃dp算法原理 力扣1137. 第 N 個泰波那契數 解析代碼1 解析代碼2 動態規劃dp算法原理 動態規劃&#xff08;Dynamic Programming&#xff09;算法的核心思想是&#xff1a;將大問題劃分為小問題進行解決&#xff0c;從而一步步獲取最優解的處理算法 動態規劃算法…

快速冪(求解原理+例題)

目錄 反復平方法&#xff08;快速冪&#xff09;&#xff1a; 代碼&#xff1a; 例題&#xff1a;快速冪求逆元 作用&#xff1a; 快速求出 的結果。 時間復雜度&#xff1a; O(logk) 如果使用一般做法&#xff0c;從1循環到k&#xff0c;時間復雜度是O(k) 反復平方法&am…

低代碼流程引擎實戰:讓表單字段成為流程節點審批人的得力助手!

在現代企業的日常運營中&#xff0c;流程審批是保障工作高效、規范進行的關鍵環節。隨著企業對于靈活性和高效性的需求不斷增長&#xff0c;傳統的固定審批人設置已無法滿足多變的業務場景。在JVS低代碼中“設置流程節點審批人為表單字段”這一功能&#xff0c;旨在通過動態配置…

C#入門:簡單數據類型和強制類型轉換

本文由 簡悅 SimpRead 轉碼&#xff0c; 原文地址 mp.weixin.qq.com 本期來講講 unity 的腳本語言 —C#&#xff0c;C# 的簡單數據類型及范圍和強制類型轉化的方法。這可是 unity 游戲開發必備技能。 1. 簡單數據類型 各個類型的范圍&#xff1a; byte -> System.Byte (字節…

黑馬點評-短信登錄業務

原理 模型如下 nginx nginx基于七層模型走的事HTTP協議&#xff0c;可以實現基于Lua直接繞開tomcat訪問redis&#xff0c;也可以作為靜態資源服務器&#xff0c;輕松扛下上萬并發&#xff0c; 負載均衡到下游tomcat服務器&#xff0c;打散流量。 我們都知道一臺4核8G的tomca…

網絡問題排查必備利器:Pingmesh

背景 當今的數字化世界離不開無處不在的網絡連接。無論是日常生活中的社交媒體、電子商務&#xff0c;還是企業級應用程序和云服務&#xff0c;我們對網絡的依賴程度越來越高。然而&#xff0c;網絡的可靠性和性能往往是一個復雜的問題&#xff0c;尤其是在具有大規模分布式架…

21.Prometheus的查詢數據類API

平凡也就兩個字: 懶和惰; 成功也就兩個字: 苦和勤; 優秀也就兩個字: 你和我。 跟著我從0學習JAVA、spring全家桶和linux運維等知識,帶你從懵懂少年走向人生巔峰,迎娶白富美! 關注微信公眾號【 IT特靠譜 】,每天都會分享技術心得~ 1.數據查詢類API 1.1.API前綴路徑說明 …

lanqiao:42點

題解&#xff1a; 1.首先&#xff0c;把字符轉成數字。 2.創建二維數組存放枚舉的結果&#xff0c;第一行一個數字13&#xff1b;第二行4個數字&#xff0c;分別是13和1的加減乘除&#xff1b;第三行16個數字&#xff0c;分別是第二行的每個數和12加減乘除的結果&#xff1b;…

基于SpringBoot的在線拍賣系統

目錄 1、 前言介紹 2、主要技術 3、系統流程和邏輯 4、系統結構設計 5、數據庫設計表 6、運行截圖(部分) 6.1管理員功能模塊 6.2用戶功能模塊 6.3前臺首頁功能模塊 7、源碼獲取 基于SpringBoot的在線拍賣系統錄像 1、 前言介紹 隨著社會的發展&#xff0c;社會的各行…

安卓玩機工具推薦----ADB狀態讀寫分區 備份分區 恢復分區 查看分區號 工具操作解析

在以往玩機過程中。很多機型備份分區 備份固件需要借助adb手動指令或者第三方手機軟件或者特定的一些工具來操作。有些朋友需要查看當前機型分區名稱和對應的分區號。此類操作我前面的博文專門說過對應的adb指令。但有些界面化的工具比較方便簡單。 相關分區同類博文&#xff…

【C++】每周一題——2024.3.3(手滑再再寫一篇)

題目 Cpp 【問題描述】 求N個字符串的最長公共子串&#xff0c;2 < N&#xff1c;&#xff1d;20&#xff0c;字符串長度不超過255。 例如&#xff1a;N&#xff1d;3&#xff0c;由鍵盤依次輸入三個字符串為 What is local bus? Name some local buses. local bus is a h…

SpringBoot源碼解讀與原理分析(三十七)SpringBoot整合WebMvc(二)DispatcherServlet的工作全流程

文章目錄 前言12.4 DispatcherServlet的工作全流程12.4.1 DispatcherServlet#service12.4.2 processRequest12.4.3 doService12.4.3.1 isIncludeRequest的判斷12.4.3.2 FlashMapManager的設計 12.4.4 doDispatch12.4.4.1 處理文件上傳請求12.4.4.2 獲取可用的Handler&#xff0…

sscanf 函數的用法

sscanf 函數是 C 語言標準庫 <stdio.h> 中的一個函數&#xff0c;用于按照指定的格式從一個字符串中讀取輸入。它的用法類似于 scanf 函數&#xff0c;但是 sscanf 從字符串中讀取輸入&#xff0c;而不是從標準輸入&#xff08;鍵盤&#xff09;中讀取輸入。 以下是 ssc…

優優嗨聚集團:美團代運營服務,商家增長的新引擎

在當今數字化時代&#xff0c;線上平臺已成為商家拓展業務、提升品牌影響力的重要渠道。美團作為國內領先的本地生活服務平臺&#xff0c;擁有龐大的用戶群體和豐富的商業資源。然而&#xff0c;對于許多商家而言&#xff0c;如何在美團平臺上進行有效運營&#xff0c;實現業務…