201期比赛题目详解
5471. 和为目标值的最大数目不重叠非空子数组数目
给你一个数组 nums
和一个整数 target
。
请你返回 非空不重叠 子数组的最大数目,且每个子数组中数字和都为 target
。
示例 1:
1 | 输入:nums = [1,1,1,1,1], target = 2 |
示例 2:
1 | 输入:nums = [-1,3,5,1,4,2,-9], target = 6 |
示例 3:
1 | 输入:nums = [-2,6,6,3,5,4,1,2,8], target = 10 |
示例 4:
1 | 输入:nums = [0,0,0], target = 0 |
解答
这道题主要考察前缀系列的问题,和 560. 和为K的子数组 题目类似,做法也基本相同
hash+前缀
- 首先需要理解一个问题,用 sum[0,i] 代表数组从 [0,i] 的加和,则存在 0 =< j < i < len ,sum[j,i]=sum[i]-sum[j]
- 根据上面的理论,可以记录每一个数据的加和,即,sum[i]
- 用当前的 sum[i] 与
target
去比较,如果在 sum[i]- target 的值等于 sum[j](0 =< j < i),则 arr[j:i] 是所求的数组。
1 | func maxNonOverlapping(nums []int, target int) int { |
5486. 切棍子的最小成本
有一根长度为 n
个单位的木棍,棍上从 0
到 n
标记了若干位置。例如,长度为 6 的棍子可以标记如下:
给你一个整数数组 cuts
,其中 cuts[i]
表示你需要将棍子切开的位置。
你可以按顺序完成切割,也可以根据需要更改切割的顺序。
每次切割的成本都是当前要切割的棍子的长度,切棍子的总成本是历次切割成本的总和。对棍子进行切割将会把一根木棍分成两根较小的木棍(这两根木棍的长度和就是切割前木棍的长度)。请参阅第一个示例以获得更直观的解释。
返回切棍子的 最小总成本 。
示例 1:
1 | 输入:n = 7, cuts = [1,3,4,5] |
示例 2:
1 | 输入:n = 9, cuts = [5,6,1,4,2] |
提示:
2 <= n <= 10^6
1 <= cuts.length <= min(n - 1, 100)
1 <= cuts[i] <= n - 1
cuts
数组中的所有整数都 互不相同
解答过程
和 312. 戳气球 较为相似,都是经典的区间动态规划题。
- 思路
- 在任意一次切割时,待切割木棍的左端点要么是原始木棍的左端点 0,要么是之前某一次切割的位置;
- 同理,待切割木棍的右端点要么是原始木棍的右端点 n,要么是之前某一次切割的位置。
- 如果我们将切割位置数组
cuts
进行排序,并在左侧添加 0,右侧添加 n,那么待切割的木棍就对应着数组中一段连续的区间 - 用
f[i][j]
表示在当前待切割的木棍的左端点为cuts[i−1]
,右端点为cuts[j+1]
时,切开的成本
举个特殊的例子:
- 如果当前是第一刀的话
f[1][n-1]
代表是左端点是0 ,右端点为 n 的切割成本 - 在 0-n 一共有 n-2 切割位置,我们随机定义一个切开的位置为
k
- 则第一刀的切割成本为
cuts[n-1]-cuts[0]
,即是木棍的长度。 - 木棍切开分成两段,会有两段 [0,k]和[k,n],切割位置为 [1,k-1]和【k+1,n-1】
- 第二刀的成本和第一刀的位置相关,只有两个可能
k-1
和n-k
,对应的位置是f[0][k-1]和f[k+1][n]
- 我们需要寻找的是就是
min(f[0][k-1],f[k+1][n])
根据上面的分析,我们可以定义一个状态转移方程:
f[i][j]= min(f[i][k-1],f[k+1][j])+(cuts[j+1]−cuts[i−1])
基本代码
1 |
|