Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies following conditions:html
where we define that subarray (L, R) represents a slice of the original array starting from the element indexed L to the element indexed R.java
Example:
數組
Input: [1,2,1,2,1,2,1] Output: True Explanation: i = 1, j = 3, k = 5. sum(0, i - 1) = sum(0, 0) = 1 sum(i + 1, j - 1) = sum(2, 2) = 1 sum(j + 1, k - 1) = sum(4, 4) = 1 sum(k + 1, n - 1) = sum(6, 6) = 1
Note:函數
class Solution { public: bool splitArray(vector<int>& nums) { if (nums.size() < 7) return false; int n = nums.size(); vector<int> sums = nums; for (int i = 1; i < n; ++i) { sums[i] = sums[i - 1] + nums[i]; } for (int j = 3; j < n - 3; ++j) { unordered_set<int> s; for (int i = 1; i < j - 1; ++i) { if (sums[i - 1] == (sums[j - 1] - sums[i])) { s.insert(sums[i - 1]); } } for (int k = j + 1; k < n - 1; ++k) { int s3 = sums[k - 1] - sums[j], s4 = sums[n - 1] - sums[k]; if (s3 == s4 && s.count(s3)) return true; } } return false; } };
下面這種解法是遞歸的暴力破解寫法,剛開始博主還納悶了,爲啥博主以前寫的迭代形式的暴力破解過不了OJ,而這個遞歸版本的確能經過呢,仔細研究了一下,發現這種解法有兩個地方作了優化。第一個優化是在for循環裏面,若是i不等於1,且當前數字和以前數字均爲0,那麼跳過這個位置,由於加上0也不會對target有任何影響,那爲何要加上i不等於1的判斷呢,由於輸入數組若是是七個0,那麼實際上應該返回true的,而若是沒有i != 1這個條件限制,後面的代碼均不會獲得執行,那麼就直接返回false了,是不對的。第二個優化的地方是在遞歸函數裏面,只有當curSum等於target了,才進一步調用遞歸函數,這樣就至關於作了剪枝處理,減小了大量的沒必要要的運算,這可能就是其能夠經過OJ的緣由吧。post
再來講下子函數for循環的終止條件 i < n - 5 + 2*cnt 是怎麼得來的,是的,這塊的確是個優化,由於i的位置是題目中三個分割點i,j,k的位置,因此其分別有本身能夠取值的範圍,因爲只有三個分割點,因此cnt的取值能夠是0,1,2。
-> 當cnt=0時,說明是第一個分割點,那麼i < n - 5,表示後面必須最少要留5個數字,由於分割點自己的數字不記入子數組之和,那麼所留的五個數字爲:數字,第二個分割點,數字,第三個分割點,數字。
-> 當cnt=1時,說明是第二個分割點,那麼i < n - 3,表示後面必須最少要留3個數字,由於分割點自己的數字不記入子數組之和,那麼所留的三個數字爲:數字,第三個分割點,數字。
-> 當cnt=2時,說明是第三個分割點,那麼i < n - 1,表示後面必須最少要留1個數字,由於分割點自己的數字不記入子數組之和,那麼所留的一個數字爲:數字。學習
解法二:優化
class Solution { public: bool splitArray(vector<int>& nums) { if (nums.size() < 7) return false; int n = nums.size(), target = 0; int sum = accumulate(nums.begin(), nums.end(), 0); for (int i = 1; i < n - 5; ++i) { if (i != 1 && nums[i] == 0 && nums[i - 1] == 0) continue; target += nums[i - 1]; if (helper(nums, target, sum - target - nums[i], i + 1, 1)) { return true; } } return false; } bool helper(vector<int>& nums, int target, int sum, int start, int cnt) { if (cnt == 3) return sum == target; int curSum = 0, n = nums.size(); for (int i = start + 1; i < n - 5 + 2 * cnt; ++i) { curSum += nums[i - 1]; if (curSum == target && helper(nums, target, sum - curSum - nums[i], i + 1, cnt + 1)) { return true; } } return false; } };
基於上面遞歸的優化方法的啓發,博主將兩個優化方法加到了以前寫的迭代的暴力破解解法上,就能經過OJ了,perfect!url
解法三:spa
class Solution { public: bool splitArray(vector<int>& nums) { int n = nums.size(); vector<int> sums = nums; for (int i = 1; i < n; ++i) { sums[i] = sums[i - 1] + nums[i]; } for (int i = 1; i <= n - 5; ++i) { if (i != 1 && nums[i] == 0 && nums[i - 1] == 0) continue; for (int j = i + 2; j <= n - 3; ++j) { if (sums[i - 1] != (sums[j - 1] - sums[i])) continue; for (int k = j + 2; k <= n - 1; ++k) { int sum3 = sums[k - 1] - sums[j]; int sum4 = sums[n - 1] - sums[k]; if (sum3 == sum4 && sum3 == sums[i - 1]) { return true; } } } } return false; } };
參考資料:code
https://leetcode.com/problems/split-array-with-equal-sum/
https://leetcode.com/problems/split-array-with-equal-sum/discuss/101484/java-solution-dfs
https://leetcode.com/problems/split-array-with-equal-sum/discuss/101481/simple-java-solution-on2