开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
LeetCode1477:找两个和为目标值且不重叠的子数组
给你一个整数数组 arr 和一个整数值 target 。
请你在 arr 中找 两个互不重叠的子数组 且它们的和都等于 target 。可能会有多种方案,请你返回满足要求的两个子数组长度和的 最小值 。
请返回满足要求的最小长度和,如果无法找到这样的两个子数组,请返回 -1 。
示例 1:
输入: arr = [3,2,2,4,3], target = 3
输出: 2
解释: 只有两个子数组和为 3 ([3] 和 [3])。它们的长度和为 2 。
示例 2:
输入: arr = [7,3,4,7], target = 7
输出: 2
解释: 尽管我们有 3 个互不重叠的子数组和为 7 ([7], [3,4] 和 [7]),但我们会选择第一个和第三个子数组,因为它们的长度和 2 是最小值。
示例 3:
输入: arr = [4,3,2,6,2,3,4], target = 6
输出: -1
解释: 我们只有一个和为 6 的子数组。
示例 4:
输入: arr = [5,5,4,4,5], target = 3
输出: -1
解释: 我们无法找到和为 3 的子数组。
示例 5:
输入: arr = [3,1,1,1,5,1,2,1], target = 3
输出: 3
解释: 注意子数组 [1,2] 和 [2,1] 不能成为一个方案因为它们重叠了。
提示:
1 <= arr[i] <= 1000
思路分析
寻找两个和为目标值且不重叠的连续子数组,注意得是连续的子数组哈 2、当明白是寻找连续的子数组和,那么首先想到这应该是滑动窗口来解决,我们先通过滑动窗口找到所有可能的数组,使用列表来存放这些数组(注意存放的数据结构得设计一下,key为数组长度,value为窗口的左值索引); 3、对列表进行排序,将长度从小到大进行排序,为什么这么排序,其实这是贪心,因为我们要找两个数组和最小的值 4、两次for遍历,去掉重叠的数组,找出两个和最小的数组
算法代码
public static int minSumOfLengths(int[] arr, int target) {
List < int[] > list = new ArrayList <> ();
int l = 0;
int r = 0;
int sum = 0;
while (r < arr.length) {
sum += arr[r];
while (sum >= target && l <= r) {
if (sum == target) {
list.add(new int[] {
l - r + 1, l
});
}
sum -= arr[l];
l++;
}
r++;
}
if (list.size() < 2) {
return -1;
}
Collections.sort(
list, ((o1, o2) - > {
return o1[0] - o2[0];
}));
int res = Integer.MAX_VALUE;
for (int i = 0; i < list.size() - 1; i++) {
int[] node = list.get(i);
// 剪枝1
if (node[0] * 2 >= res) {
break;
}
for (int j = i + 1; j < list.size(); j++) {
int[] element = list.get(j);
int bigger = node[1] <= element[1] ? 0 : -1;
if (bigger == 0 && element[1] <= (node[1] + node[0] - 1)) {
continue;
}
if (bigger == -1 && node[1] <= (element[1] + element[0] - 1)) {
continue;
}
res = Math.min(res, node[0] + element[0]);
// 剪枝2
break;
}
}
return res == Integer.MAX_VALUE ? -1 : res;
}
结果详情
算法复杂度
- 空间复杂度:
- 时间复杂度:
在掘金(JUEJIN)一起进步,一起成长!