找两个和为目标值且不重叠的子数组
难度:
标签:
题目描述
代码结果
运行时间: 134 ms, 内存: 29.4 MB
/*
* Given an integer array arr and an integer target,
* find two non-overlapping subarrays such that their sums are equal to target.
* Return the minimum sum of their lengths. If no such subarrays exist, return -1.
* Java Stream API is not well suited for this type of problem due to its complex state management.
* This implementation is provided for completeness but uses traditional loops internally.
*/
public class Solution {
public int minSumOfLengths(int[] arr, int target) {
int n = arr.length;
int[] prefixMin = new int[n];
Arrays.fill(prefixMin, Integer.MAX_VALUE);
int sum = 0;
int minLen = Integer.MAX_VALUE;
int result = Integer.MAX_VALUE;
Map<Integer, Integer> map = new HashMap<>();
map.put(0, -1);
IntStream.range(0, n).forEach(i -> {
sum += arr[i];
if (map.containsKey(sum - target)) {
int start = map.get(sum - target) + 1;
int len = i - start + 1;
if (start > 0 && prefixMin[start - 1] != Integer.MAX_VALUE) {
result = Math.min(result, len + prefixMin[start - 1]);
}
minLen = Math.min(minLen, len);
}
prefixMin[i] = minLen;
map.put(sum, i);
});
return result == Integer.MAX_VALUE ? -1 : result;
}
}
解释
方法:
此题解采用了双指针和滑动窗口的方法来找到和为target的子数组。利用left和right指针控制窗口的左右边界。当窗口内元素之和小于target时右移right扩大窗口;当窗口内之和大于target时,右移left缩小窗口。每次窗口内之和等于target时,检查是否存在之前记录的非重叠子数组,如果存在,则更新可能的最小长度。为了记录和跟踪非重叠的子数组,使用deque(双端队列)来存储每个有效的子数组的起始和终止位置,并维护一个最小长度变量。当发现更短的子数组时,更新此最小值。最终,如果有符合条件的两个子数组,返回它们长度之和的最小值;否则返回-1。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
在算法中,如何确保找到的两个子数组确实是互不重叠的?
▷🦆
算法中使用的双端队列是如何帮助寻找最小长度和的?即,队列中存储的子数组信息如何被利用?
▷🦆
为什么在发现窗口和等于目标值时,首先要检查并移除队列中所有结束位置小于等于当前左指针的子数组?
▷🦆
在更新非重叠子数组的最小长度`mn`时,为什么选择从队列中移除元素,而这些元素的结束位置小于等于当前的`left`指针?
▷