Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies following conditions:
- 0 < i, i + 1 < j, j + 1 < k < n - 1
- Sum of subarrays (0, i - 1), (i + 1, j - 1), (j + 1, k - 1) and (k + 1, n - 1) should be equal.
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.
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:
- 1 <= n <= 2000.
- Elements in the given array will be in range [-1,000,000, 1,000,000].
将数组分割成和相等的子数组。
题意是给一个数组,请你找是否数组中存在这样一个三元组(i, j, k)满足i < j < k, (0, i - 1), (i + 1, j - 1), (j + 1, k - 1), (k + 1, n - 1)这四部分的数组和相等。注意这三个指针指向的值不包含在这四个区间里,也就是说比如你找到第一个指针i的时候,nums[i]是不会计算在(0, i - 1)或者(i + 1, j - 1)这两部分的子数组的和里面的。
我这里给出的是前缀和 + hashset的思路。首先排除corner case是input数组长度小于7的情形。比如第一个例子,如果input数组长度小于7,你是无法满足条件找到这三个指针的位置的,所以长度小于7的数组是不行的。
接着处理正常的case,创建一个数组记录原数组的前缀和,这样便于计算中间部分的数组和。
接着自然是找每个指针的位置。但是你会发现如果先找第一个指针i的位置,虽然i的范围可以被确定下来,但是复杂度会很高,因为确定剩下两个指针的位置也是需要同样的复杂度,这一整套下来的复杂度起码是O(n^3)起跳。事实上这种做法也是无法通过OJ的。这里我提供一个优化的思路,我们可以先尝试确定第二个指针j的位置。一旦j的位置能确定下来,对于i指针来说,就是在0 - j之间two pointer夹逼找;同理对于k指针来说,就是在j - nums[nums.length - 1]之间two pointer夹逼找。其他部分可参见代码注释。
时间O(n^2)
空间O(n)
Java实现
1 class Solution { 2 public boolean splitArray(int[] nums) { 3 if (nums.length < 7) { 4 return false; 5 } 6 7 int[] sum = new int[nums.length]; 8 sum[0] = nums[0]; 9 // create sum array: each sum has sum from 1 to i 10 for (int i = 1; i < nums.length; i++) 11 sum[i] = sum[i - 1] + nums[i]; 12 13 // for j - middle cut 14 for (int j = 3; j < nums.length - 3; j++) { 15 HashSet<Integer> set = new HashSet<>(); 16 // for i - left cut 17 for (int i = 1; i < j - 1; i++) { 18 int sum1 = sum[i - 1]; 19 int sum2 = sum[j - 1] - sum[i]; 20 if (sum1 == sum2) 21 set.add(sum1); // add potential answers into set 22 } 23 // for k - right cut 24 for (int k = j + 2; k < nums.length - 1; k++) { 25 int sum3 = sum[k - 1] - sum[j]; 26 int sum4 = sum[nums.length - 1] - sum[k]; 27 if (sum3 == sum4 && set.contains(sum3)) // 28 return true; 29 } 30 31 } 32 return false; 33 } 34 }