給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。
注意:
每個陣列中的元素不會超過 100陣列的大小不會超過 200
示例 1:
輸入: [1, 5, 11, 5]輸出:
true
解釋: 陣列可以分割成 [1, 5, 5] 和 [11].
示例 2:
輸入: [1, 2, 3, 5]輸出:
false
解釋: 陣列不能分割成兩個元素和相等的子集.
每個元素都有選和不選兩種可能,如果當前和等於總和的一般,直接返回,標記置為true,
如果當前和大於sum的一半,也直接返回,因為當前和已經超過了一半,沒必要往下加了
1class
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
1class
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]就可以開始不用向下遍歷了。所以減少了迭代次數,所以同時也降低了時間複雜度。
1class
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分。我...