携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情 >>
和为目标值且不重叠的非空子数组的最大数目
给你一个数组 nums 和一个整数 target 。
请你返回 非空不重叠 子数组的最大数目,且每个子数组中数字和都为 target 。
示例1:
输入:nums = [1,1,1,1,1], target = 2
输出:2
解释:总共有 2 个不重叠子数组(加粗数字表示) [1,1,1,1,1] ,它们的和为目标值 2 。
示例2:
输入:nums = [-1,3,5,1,4,2,-9], target = 6
输出:2
解释:总共有 3 个子数组和为 6 。
([5,1], [4,2], [3,5,1,4,2,-9]) 但只有前 2 个是不重叠的。
示例3:
输入: nums = [-2,6,6,3,5,4,1,2,8], target = 10
输出: 3
示例4:
输入: nums = [0,0,0], target = 0
输出: 3
提示:
1 <= nums.length <= 10^5-10^4 <= nums[i] <= 10^40 <= target <= 10^6
解题思路:
设数组nums的长度为len
dp[i]代表从数组nums的下标0到i的子数组最大不重叠子数组的数目
状态转移方程
当nums[i]作为一个子数组sub时,能得到的最大值dp[i-1] + (如果sub累加和为target则+1,否则+0)
当nums[i]和nums[i-1]作为一个子数组sub时,能得到的最大值dp[i-2] + (如果sub累加和为target则+1,否则+0)
以此类推
dp[i] = max{dp[i-1] + (sum{nums[i]} == target ? 1 : 0) , dp[i-2] + (sum{nums[i], nums[i + 1]} == target ? 1 : 0), .... , (sum{nums[i], nums[i + 1], ...., nums[len - 1]} == target ? 1 : 0)}
其中求和可以通过前缀和的方法的在O(1)的时间内求出
所以求解每个dp[i]都需要遍历dp[i-1], dp[i-2], dp[i-3]到结尾,时间复杂度O(n^2)
我的答案:
/**
* @param {number[]} nums
* @param {number} target
* @return {number}
*/
var maxNonOverlapping = function(nums, target) {
const len = nums.length
const map = new Map()
const dp = Array(len).fill(0)
let preSum = 0
map.set(preSum, -1)
for(let i = 0; i < len; i++){
preSum += nums[i]
let p1 = i - 1 >= 0 ? dp[i - 1] : 0
const index = map.get(preSum - target)
let p2 = 0
if(index != undefined){
p2 = 1 + (index >= 0 ? dp[index] : 0)
}else{
p2 = nums[i] == target ? 1 : 0
}
dp[i] = Math.max(p1, p2)
map.set(preSum, i)
}
return dp[len - 1]
};
最后
如果有更好的解法或者思路, 欢迎在评论区和我交流~ ღ( ´・ᴗ・` )