leetcode hot 100 分割等和子集

2022-03-29 09:27:39 字數 3498 閱讀 6341

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

注意:

每個陣列中的元素不會超過 100陣列的大小不會超過 200

示例 1:

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

輸出:

true

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

示例 2:

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

輸出:

false

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

每個元素都有選和不選兩種可能,如果當前和等於總和的一般,直接返回,標記置為true,

如果當前和大於sum的一半,也直接返回,因為當前和已經超過了一半,沒必要往下加了

1

class

solution

11//

如果和是奇數,那直接返回false, 因為奇數不可能分割成兩個和相等的子集

12if(sum % 2 == 1)

1516

//使用回溯判斷設定標記位

17 traceback(0, 0, nums, sum);

18return

flag; 19}

2021

public

void traceback(int nowsum, int nowindex, int nums, int

sum)

25if(nowsum >= sum /2)

29return;30

}31//選

32 traceback(nowsum + nums[nowindex], nowindex + 1, nums, sum);

33//

不選34 traceback(nowsum, nowindex + 1, nums, sum);35}

36 }

超時,只通過了36/115個測試用例

時間複雜度:o(2n), 每個數都有選和不選兩種可能,所以把所有情況都遍歷了一遍,時間複雜度為o(2n)。

空間複雜度:o(n)。遞迴棧的深度最大為o(n)。

思路參考:

dp[i][j]表示前i個數是否能湊出和為j的數

當不算第i個數時,dp[i][j] = dp[i-1][j];

選第i個數數時,dp[i][j] = dp[i-1][j-nums[i]]

所以狀態轉移方程為:dp[i][j] = dp[i-1][j] || dp[i-1][j - nums[i]];

初值:dp[i][0]每個數都可以選和不選,所以dp[i][0] = true,即前i數都不選,則和為0,當單個元素選的時候,dp[i][nums[i]] = true, 但是在賦初值的過程中,需要判斷nums[i]是否大於target, 如果大於則陣列會越界,並且如果存在單個數字大於和的一半,那肯定就不能分割成兩個等值的陣列了,直接返回false 即可。

剪枝:如果dp[i][target]為true, 那dp[n-1][target]肯定為true

1

class

solution

11//

如果和是奇數,那直接返回false, 因為奇數不可能分割成兩個和相等的子集

12if(sum % 2 == 1)

1516

int target = sum / 2;

17boolean dp = new

boolean[len][target + 1];

1819

for(int i = 0; i < len; i++)

24 dp[i][nums[i]] = true; //

單個數字選25}

2627

for(int i = 1; i < len; i++)

32 dp[i][j] = dp[i - 1][j];

33if(j - nums[i] >= 0)36}

37}38return dp[len - 1][target]; 39}

40 }

leetcode 執行用時:63 ms > 12.98%, 記憶體消耗:39 mb > 42.98%

時間複雜度:o(nc)。c是和的一半,求出了所有的dp[i][j], 所以時間複雜度為o(nc)。

空間複雜度:o(nc)。需要乙個大小為 (n * (c+1))的陣列,所以空間複雜度為o(nc)。

可以看到,dp[i][j] = dp[i - 1][j] || dp[i-1][j-nums[i]], dp[i][j]之和上一行的dp[i-1]有關,所以只要用乙個大小為 (target + 1)一維陣列,記錄下上一行的dp值即可。但是因為 dp[i][j]用到了dp[i-1][j-nums[i]], 所以為們應該從target到0, 逆序生成新的一行dp值,因為如果我們正序遍歷的話,那dp[i][j-nums[i]]就會被更新成新的一行的值,後面使用該資料的後就出錯了,我們需要的上乙個行的值。

因為倒序遍歷,且 j-nums[i]作為下標,所以為了下標不越界,當 j < nums[i]就可以開始不用向下遍歷了。所以減少了迭代次數,所以同時也降低了時間複雜度。

1

class

solution

11//

如果和是奇數,那直接返回false, 因為奇數不可能分割成兩個和相等的子集

12if(sum % 2 == 1)

1516

int target = sum / 2;

17boolean dp = new

boolean[target + 1];

1819 dp[0] = true; //

第0個數字不選

20if(nums[0] > target)

23 dp[nums[0]] = true; //

第0個數字選

2425

for(int i = 1; i < len; i++)

30 dp[j] = dp[j] || dp[j -nums[i]];31}

32}33return

dp[target]; 34}

35 }

leetcode 執行用時:20 ms > 82.32%, 記憶體消耗:37.9 mb > 81.35%

時間複雜度:o(nc)。同樣求出了每個i對應的 dp[j], 但是因為 j > nums[i]時即可停止本輪迭代,所以一定程度上減少了迭代次數,所以執行時間比思路二短一些。但是總的時間複雜度還是o(nc)。

空間複雜度:o(c)。需要乙個大小為 c+1的陣列,所以空間複雜度為o(c)。

LeetCode Hot 100 最長回文子串

新年的刷的第一題,題目如下 給你乙個字串 s,找到 s 中最長的回文子串。示例 1 輸入 s babad 輸出 bab 解釋 aba 同樣是符合題意的答案。示例 2 輸入 s cbbd 輸出 bb 示例 3 輸入 s a 輸出 a 示例 4 輸入 s ac 輸出 a 1 s.length 1000 ...

leetcode hot100刷題第四天

二 搜尋旋轉排序陣列 leetcode 33 三 在排序陣列中查詢元素第乙個和最後乙個位置 leetcode 34 四 組合總和 leetcode 39 五 接雨水 leetcode 42 總結給定乙個只包含 和 的字串,找出最長的包含有效括號的子串的長度。示例 1 輸入 輸出 2 解釋 最長有效括...

100分的情書

親愛的 我對1見鍾情,絕無2心,想照顧3生3世,因為我偷偷上的 4次,那迷人的5官,總讓我6神無主,一顆心7上8下,99不能平息,如果我的滿分是10分,一定不止11分,起碼也該有12分,只可惜我討厭13這個數字,不然一定有14分,如果再加上的聰明那又不止15分,16分一定還嫌少,所以我給了17分。我...