1477.找两个和为目标值且不重叠的子数组
题目描述
给你一个整数数组arr
和一个整数值target
。
请你在arr
中找两个互不重叠的子数组且它们的和都等于target
。可能会有多种方案,请你返回满足要求的两个子数组长度和的最小值。
请返回满足要求的最小长度和,如多无法找到这样的两个子数组,请返回**-1**。
思路与算法
如果存在多个以i
下标结尾的子数组满足要求,则选择其中长度最短的那一个。因为如果一个较长的子数组可以作为答案中的一部分,换成一个较短的子数组,也同样成立,同时满足总和更短。(贪心的思想)
首先,使用一个
map
来记录<前缀和,结尾下标>
的映射信息。一个vector
记录当前下标之前满足要求的最短子数组长度。利用
当前前缀和 - target
判断是否存在目标子数组区间。若存在,则得出对应子数组长度,并与当前位置之前的最短子数组长度比较,将较小值存入一个vector
中;否则,则存入0
。得到一个满足要求的最短子数组后,以该子数组的起始下标为结尾,搜索
vector
中是否存在满足要求的第二个子数组,若存在,则记录两子数组长度和,并与当前最短的两个子数组之和进行比较,取小。经过一轮遍历之后,输出结果。
代码
class Solution { public: int minSumOfLengths(vector<int>& arr, int target) { unordered_map<int, int> M; // 用于<前缀和,结尾下标>的映射 int t = 0; int ans = 2e9; vector<int> len; // 记录到每个位置,和为target的最短子数组的长度 int mi = 0; // 当前满足和为target的最短子数组的长度 M[0] = -1; for(int i = 0; i < arr.size(); i++){ t += arr[i]; M[t] = i; if(M.count(t - target)){ int l = M[t-target]; int x = i - l; if(mi == 0) mi = x; else mi = min(mi, x); len.push_back(mi); if(l != -1 && len[l] != 0){ // 不是第一个满足条件的子数组 ans = min(ans, len[l] + x); } }else{ len.push_back(mi); } } if(ans == 2e9) return -1; return ans; } };
复杂度分析
时间复杂度:一轮循环遍历,时间复杂度为O(n)。
空间复杂度:用于哈希映射的
map
,以及记录目标子数组长度的vector
,故空间复杂度为O(n)。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!