日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【LeetCode笔记】416. 分割等和子集(Java、动态规划、背包问题、滚动数组)

發(fā)布時間:2024/7/23 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【LeetCode笔记】416. 分割等和子集(Java、动态规划、背包问题、滚动数组) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 題目描述
  • 思路 && 代碼
      • 1. 動態(tài)規(guī)劃 O(nc) 、O(nc)
      • 2. 結(jié)合滾動數(shù)組 O(nc)、O(c)
      • 二刷

打卡第十四天~熬夜也得把題目補上= =

題目描述

  • 初看題目,想到的思路是用記憶化DFS來找結(jié)果來著。。看了題解才知道是背包問題= =

思路 && 代碼

1. 動態(tài)規(guī)劃 O(nc) 、O(nc)

  • 參考了liweiwei的這篇題解,里面給背包問題講了一些相關(guān)知識~
  • 時空復雜度: n 是 nums 的長度,c 是 sum 的長度。
  • dp[i][j]:從[0, i]下標組成的數(shù)集里選取元素相加,能否構(gòu)成 j 。
  • 狀態(tài)轉(zhuǎn)移方程:【[0, i - 1] 可以構(gòu)成 j】| 【[0, i - 1] 可以構(gòu)成 j - nums[i]】,滿足任一種情況,都可以保證 dp[i][j] == true,因此這里采用 |=
class Solution {public boolean canPartition(int[] nums) {// 題意轉(zhuǎn)化:找到一個集合,滿足其和等于 nums 總和的一半 sum / 2int sum = 0;for(int num : nums) {sum += num;}// 奇數(shù),肯定無法滿足 sum / 2if(sum % 2 == 1) {return false;}// [0 ~ i 范圍的元素][背包容量(包括0)]int target = sum / 2;boolean[][] dp = new boolean[nums.length][target + 1];// 1. 邊界:第一個元素,只能滿足對應的容量if(nums[0] <= target) {dp[0][nums[0]] = true;}// 2. 狀態(tài)轉(zhuǎn)移for(int i = 1; i < nums.length; i++) {for(int j = 0; j <= target; j++) {// part 1: 先把上一輪的結(jié)果繼承下來再說dp[i][j] = dp[i - 1][j];// part 2: 狀態(tài)轉(zhuǎn)移方程:看[0, i - 1]能不能滿足 j - nums[i],再補上 nums[j]if(nums[i] <= j) {dp[i][j] |= dp[i - 1][j - nums[i]];}}}return dp[nums.length - 1][target];} }

2. 結(jié)合滾動數(shù)組 O(nc)、O?

  • 在1的基礎(chǔ)上,通過滾動數(shù)組來減少空間復雜度。在劍指Offer 47 禮物的最大值里,也有用到這個方法~。
  • 加入 if(dp[target]) 的判斷實現(xiàn)剪枝效果,可以打敗98%+,這里為了看起來簡潔就不加上了
  • 注意:逆序是為了達到無后效性的效果。如果正序,會導致后面的列用到的不是上一行的結(jié)果,而是當前行的結(jié)果,會導致出錯(可以畫圖理解一下,或者看上面1提到的題解的解釋)
class Solution {public boolean canPartition(int[] nums) {// 題意轉(zhuǎn)化:找到一個集合,滿足其和等于 nums 總和的一半 sum / 2int sum = 0;for(int num : nums) {sum += num;}// 奇數(shù),肯定無法滿足 sum / 2if(sum % 2 == 1) {return false;}// [0 ~ i 范圍的元素][背包容量(包括0)]int target = sum / 2;boolean[] dp = new boolean[target + 1];// 1. 邊界:第一個元素,只能滿足對應的容量if(nums[0] <= target) {dp[nums[0]] = true;}// 2. 狀態(tài)轉(zhuǎn)移for(int i = 1; i < nums.length; i++) {// 逆序,達到無后效性的效果for(int j = target; j >= 0; j--) {// part 1: 先把上一輪的結(jié)果繼承下來再說(滾動數(shù)組不用考慮)// part 2: 狀態(tài)轉(zhuǎn)移方程:看[0, i - 1]能不能滿足 j - nums[i],再補上 nums[j]if(nums[i] <= j) {dp[j] |= dp[j - nums[i]];}}}return dp[target];} }

二刷

背包!
你就說你選不選吧(指元素)
你要能 true 我肯定選啊

  • O(nc)、O(nc)
class Solution {public boolean canPartition(int[] nums) {int sum = 0;for(int num : nums) {sum += num;}if((sum & 1) == 1) {return false;}// dp[i][j]:從 [0, i] 的下標中,能找到和為 j 的值int target = sum / 2;boolean[][] dp = new boolean[nums.length][target + 1];if(nums[0] <= target) {dp[0][nums[0]] = true;}for(int i = 1; i < nums.length; i++) {for(int j = 0; j <= target; j++) {// 繼承結(jié)果 | 當前可行dp[i][j] = (dp[i - 1][j]) | (nums[i] <= j ? dp[i - 1][j - nums[i]] : false);}}return dp[nums.length - 1][target];} }
  • 滾動數(shù)組:逆序降低空間復雜度
class Solution {public boolean canPartition(int[] nums) {int sum = 0;for(int num : nums) {sum += num;}if((sum & 1) == 1) {return false;}int target = sum / 2;boolean[] dp = new boolean[target + 1];if(nums[0] <= target) {dp[nums[0]] = true;}for(int i = 1; i < nums.length; i++) {for(int j = target; j >= 0; j--) {dp[j] |= (nums[i] <= j ? dp[j - nums[i]] : false);}}return dp[target];} }

總結(jié)

以上是生活随笔為你收集整理的【LeetCode笔记】416. 分割等和子集(Java、动态规划、背包问题、滚动数组)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。