题号 | 做出 | 未做 |
---|---|---|
1544 | √ | |
1545 | √ | |
1546 | √ | |
1547 | √ |
通过率:50%
1544 整理字符串
1545
1546 和为目标值的最大数目不重叠非空子数组数目
问题的本质
int maxNonOverlapping(vector<int>& nums, int target) {
...
//显然不论如何都是要遍历每一个元素的
for(auto i : nums){
//问题的本质:对于每一个nums中的元素来说,都有且仅有2种选择,要么单独判断是否等于target,要么加上之前的”连续“元素和判断是否等于target。
}
...
}
for(auto i : nums){
}
其实这里有动态规划的思想在里面。即 d p [ i ] dp[i] dp[i]表示下标在[0,i]之间的元素的目标和。则 d p [ i ] dp[i] dp[i]肯定是在 d p [ i − 1 ] dp[i-1] dp[i−1]的基础上得到的,但是与 d p [ i − 1 ] dp[i-1] dp[i−1]的具体关系要根据 n u m [ i ] num[i] num[i]和 i i i之前的连续下标的元素和(记为 s u m j sum_{j} sumj)的关系。
- 如果存在 j , 使 得 f o r ( i t e m = n u m [ j ] − > n u m [ i ] ) s u m + = i t e m ; s u m = t a r g e t , 则 d p [ i ] = d p [ i − 1 ] + 1 j,使得for(item = num[j] -> num[i]) {sum += item;} sum = target, 则dp[i] = dp[i-1]+1 j,使得for(item=num[j]−>num[i])sum+=item;sum=target,则dp[i]=dp[i−1]+1;
- 否则dp[i] = dp[i-1];
问题的求解思路
解决的关键在于如何实现 f o r ( i t e m = n u m [ j ] − > n u m [ i ] ) s u m + = i t e m ; s u m = t a r g e t , 则 d p [ i ] = d p [ i − 1 ] + 1 for(item = num[j] -> num[i]) {sum += item;} sum = target, 则dp[i] = dp[i-1]+1 for(item=num[j]−>num[i])sum+=item;sum=target,则dp[i]=dp[i−1]+1 。这个问题看上去很复杂,其实非常的简单。小学加减法问题。即 s u m [ x , z ] = s u m [ y , z ] + s u m [ x , y ) , 其 中 x < y < z sum_{[x,z]} = sum_{[y,z]} + sum_{[x,y)},其中x < y < z sum[x,z]=sum[y,z]+sum[x,y),其中x<y<z,对其变形得 t a r g e t = s u m [ x , z ] − s u m [ x , y ) target = sum_{[x,z]}-sum_{[x,y)} target=sum[x,z]−sum[x,y)如果找到了对应的 x , y x,y x,y则 d p [ i ] = d p [ i − 1 ] + 1 dp[i] = dp[i-1]+1 dp[i]=dp[i−1]+1。否则 d p [ i ] = d p [ i − 1 ] dp[i] = dp[i-1] dp[i]=dp[i−1]
算法实现
s u m [ x , y ) sum_{[x,y)} sum[x,y)是需要存储的,可选的数据结构有:集合,数组等线性随机存取的数据结构都可。
class Solution {
public:
int maxNonOverlapping(vector<int>& nums, int target) {
int ans = 0, sum = 0;
set<int> store_sum_xy;
store_sum_xy.insert(0);
for(auto &i : nums){
sum += i;
if(store_sum_xy.find(sum - target) != store_sum_xy.end()){
++ans;
sum = 0;
store_sum_xy.clear();
}
store_sum_xy.insert(sum);
}
return ans;
}
};