力扣分割等和子集

2021-10-24 16:15:40 字數 2938 閱讀 3755

給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。

注意:每個陣列中的元素不會超過 100

陣列的大小不會超過 200

示例 1:

輸入: [1, 5, 11, 5]

輸出: true

解釋: 陣列可以分割成 [1, 5, 5] 和 [11].

示例 2:

輸入: [1, 2, 3, 5]

輸出: false

解釋: 陣列不能分割成兩個元素和相等的子集.

此題不能用排序然後基於貪心演算法依次將每乙個元素新增至當前元素和較小的子集中這種類似的演算法,這種演算法可以輕鬆的舉出反例

這道題可以換一種表述:給定乙個只包含正整數的非空陣列nums,判斷是否可以從陣列中選出一些數字,使得這些數字的和等於整個陣列的元素和的一半。因此這個問題可以轉換成「0-1揹包問題」。這道題與傳統的「0-10−1 揹包問題」的區別在於,傳統的「0-1揹包問題」要求選取的物品的重量之和不能超過揹包的總容量,這道題則要求選取的數字的和恰好等於整個陣列的元素和的一半。類似於傳統的「0-1揹包問題」,可以使用動態規劃求解。

在使用動態規劃求解之前,首先需要進行以下判斷。

建立二維陣列 dp,包含 n 行 tag+1 列,其中 dp [ i ] [ j ]表示從陣列的 [ 0 ,i ] 下標範圍內選取若干個正整數(可以是 0 個),是否存在一種選取方案使得被選取的正整數的和等於 j。初始時,dp 中的全部元素都是false。

在定義狀態之後,需要考慮邊界情況。以下兩種情況都屬於邊界情況。

對於i>0 且 j>0 的情況,如何確定 dp[i] [j] 的值?需要分別考慮以下兩種情況。

最終得到dp[n−1] [tag] 即為答案。

ac**如下:

class

solution

int sum =

accumulate

(nums.

begin()

, nums.

end(),

0);int maxnum =

*max_element

(nums.

begin()

, nums.

end())

;if(sum &1)

int target = sum /2;

if(maxnum > target)

vectorint>>

dp(n, vector<

int>

(target +1,

0));

for(

int i =

0; i < n; i++

) dp[0]

[nums[0]

]=true

;for

(int i =

1; i < n; i++

)else}}

return dp[n -1]

[target];}

};

上述**的時間複雜度為o(n*tag),但是可以發現計算dp時每一行的dp都只與上一行的dp值有關,因此只需要乙個一維陣列即可將空間複雜度降到o(tag),此時的轉移方程為dp[j]=dp[j]|dp[j-nums[i]], 但要注意的是第二層的迴圈需要從大到小計算,因為如果我們從小到大更新dp值,那麼在計算dp[j]值的時候, dp[j-nums[i]]已經是被更新過的狀態,不再是上一行的dp值.

ac**如下:

bool

canpartition

(int

* nums,

int numssize)

tag=sum/2;

//求出這個陣列的和的一半,如果能找到一些數的和等於tag則滿足題意

if(sum%2==

1||maxn>tag)

return

false

;//如果sum為奇數或者陣列中的最大數都比tag大的話則不滿足題意,直接返回false

bool dp[tag+1]

;memset

(dp,

false

,sizeof

(dp));

dp[0]

=true

;//設定邊界條件

for(

int i=

0;ireturn dp[tag]

;}

先求出該陣列的和, 再將其分成兩堆, 深度優先搜尋遍歷陣列, 只要將最後乙個數加到任意一堆使得符合題意即可,然後再遞迴呼叫

ac**如下:

int

cmp(

const

void

*a,const

void

*b)int

dfs(

int*nums,

int pos,

int taget,

int sum1,

int sum2)

if(sum1 > taget || sum2 > taget)

return

dfs(nums, pos +

1, taget, sum1 + nums[pos]

, sum2)

||dfs

(nums, pos +

1, taget, sum1, sum2 + nums[pos]);

}bool

canpartition

(int

* nums,

int numssize)

if(sum %2!=

0)sum /=2

;qsort

(nums, numssize,

sizeof

(int

), cmp)

;return

dfs(nums,

0, sum,0,

0);}

分割等和子集 力扣

題意理解 給定乙個陣列,求將其分成兩組,是否存在兩組內部元素的和相等。問題分析 動規問題轉化為 給定一組元素,求是否存在這組元素中任意數量的元素加起來和等於這組元素的和的一半?其他鏈結 bool canpartition vector nums sum sum 2 int count nums.si...

分割等和子集

給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。示例 1 輸入 1 5,11 5 輸出 true 解釋 陣列可以分割成 1,5,5 和 11 示例 2 輸入 1 2,3 5 輸出 false 解釋 陣列不能分割成兩個元素和相等的子集.思路 1.首先求陣列總...

分割等和子集

給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。注意 每個陣列中的元素不會超過 100 陣列的大小不會超過 200 示例 1 輸入 1,5,11,5 輸出 true 解釋 陣列可以分割成 1,5,5 和 11 示例 2 輸入 1,2,3,5 輸出 fals...