LeetCode-day42-3117. 划分数组得到最小的值之和
题目描述
给你两个数组 nums 和 andValues,长度分别为 n 和 m。
数组的 值 等于该数组的 最后一个 元素。
你需要将 nums 划分为 m 个 不相交的连续 子数组,对于第 ith 个子数组 [li, ri],子数组元素的按位 AND 运算结果等于 andValues[i],换句话说,对所有的 1 <= i <= m,nums[li] & nums[li + 1] & … & nums[ri] == andValues[i] ,其中 & 表示按位 AND 运算符。
返回将 nums 划分为 m 个子数组所能得到的可能的 最小 子数组 值 之和。如果无法完成这样的划分,则返回 -1 。
示例
示例1:
示例2:
示例3:
思路
记忆化搜索
递归边界:
- 如果 n−i<m−j,那么剩余元素不足,无法划分,返回 ∞。
- 如果 j=m 且 i<n,还有元素没有划分,返回 ∞。
- 如果 j=m 且 i=n,划分成功,返回 0。
递归入口:
- dfs(0,0,−1),即答案。如果答案是 ∞ 则返回 −1。
代码
class Solution:
def minimumValueSum(self, nums: List[int], andValues: List[int]) -> int:
n, m = len(nums), len(andValues)
@cache
def dfs(i: int, j: int, and_: int) -> int:
if n - i < m - j: # 剩余元素不足
return inf
if j == m: # 分了 m 段
return 0 if i == n else inf
and_ &= nums[i]
res = dfs(i + 1, j, and_) # 不划分
if and_ == andValues[j]: # 划分,nums[i] 是这一段的最后一个数
res = min(res, dfs(i + 1, j + 1, -1) + nums[i])
return res
ans = dfs(0, 0, -1)
return ans if ans < inf else -1