1.题目描述
给你一个下标从 0 开始、长度为 n
的整数数组 nums
,和一个整数 k
。
你可以执行下述 递增 运算 任意 次(可以是 0 次):
- 从范围
[0, n - 1]
中选择一个下标i
,并将nums[i]
的值加1
。
如果数组中任何长度 大于或等于 3 的子数组,其 最大 元素都大于或等于 k
,则认为数组是一个 美丽数组 。
以整数形式返回使数组变为 美丽数组 需要执行的 最小 递增运算数。
子数组是数组中的一个连续 非空 元素序列。
2.解题思路
记忆化搜索
题目要求【任何长度大于或等于3】的子数组【>=k】,那么等价于要求任何长度大于3的子数组,包含至少一个>=k的数。进一步抽象化:选一个【子序列】,子序列的所有元素都需要变成>=k的数,子序列的相邻元素不能间隔太大,相邻元素的下标差要<=3。
定义
dfs(i, j)表示现在要处理nums[0]到nums[i]这段子数组,并且num[i]右边有j个没有变大的数。
比如这个例子,对于当前i:右边只有一个没有变大的数
利用这种定义,我们就能从dfs(i, j)转移到i - 1
从后往前枚举
选:`dfs[i][j] = dfs(i - 1, 0) + max(k - nums[i], 0)`
不选:`if (j < 2) dfs[i][j] = dfs(i - 1, j + 1)`,对于i - 1,右边多一个不选的数。前提是j < 2,如果i - 1右边已经有2个没有选的数,那么下一个就必须选,不能不选。
递归边界
当 i < 0 的时候,返回0
递归入口
dfs(n - 1, 0)
3.AC_code
class Solution:
def minIncrementOperations(self, nums: List[int], k: int) -> int:
n = len(nums)
@cache
def dfs(i: int, j: int):
if i < 0:
return 0
res = dfs(i - 1, 0) + max(k - nums[i], 0)
if j < 2:
res = min(res, dfs(i - 1, j + 1))
return res
return dfs(n - 1, 0)