3599. 划分数组以最小化异或值

题目地址(3599. 划分数组以最小化异或值)

https://leetcode.cn/problems/partition-array-to-minimize-xor/

题目描述

给定一个整数数组 nums 和一个整数 k,你需要将数组划分为 恰好 k 个非空子数组,使得所有子数组的异或值中的 最大值 最小化。返回这个最小的最大异或值。

示例 1:

输入:nums = [0, 1, 2], k = 2
输出:2
解释:可以将数组划分为 [0, 1] 和 [2],异或值分别为 1 和 2,最大值为 2。

示例 2:

输入:nums = [1, 2, 3, 4], k = 3
输出:4
解释:可以将数组划分为 [1, 2], [3], [4],异或值分别为 3, 3, 4,最大值为 4。

约束:

  • (1 \leq k \leq nums.length \leq 1000)

  • (0 \leq nums[i] < 2^{30})

思路

首先,看数据规模,不难想到解法应该是需要多重循环的那种。

其次,题目是极小化最大值,先考虑能不能用二分。(极大化最小值也是一样的)。想了一下,似乎没好的思路。

然后,接着想,对于每一个元素 nums[i] 是不是要么合并到前面的子数组,要么单独开辟一个新的子数组。这好像是典型的”选择“问题,应该用动态规划。想到这里就差不多解决了一大半困难了。

我们可以通过两种方法解决这个问题:

  • 方法一:记忆化递归(Top-Down DP)

    • 状态定义:定义 dp(i, k) 表示从第 i 个元素开始,将剩余部分划分为 k 个子数组时,能得到的最小最大异或值。

    • 递推关系:对于每个起始位置 i,我们可以尝试不同的结束位置 j,计算子数组 [i, j] 的异或值,然后递归处理剩余部分。最终结果是所有可能划分中,最大异或值的最小值。

    • 剪枝优化:如果当前计算的异或值已经大于当前最优解,则无需继续递归。

    • 缺点:由于递归深度和重复计算较多,在大数据规模下可能会超时。

  • 方法二:动态规划(Bottom-Up DP)

    • 状态定义:定义 dp[i][j] 表示从第 i 个元素开始,划分为 j 个子数组时,能得到的最小最大异或值。

    • 递推关系:从后向前遍历数组,对于每个位置 i 和剩余划分数 j,枚举子数组的结束位置,计算异或值并更新最优解。

    • 初始化dp[n][0] = 0(没有元素时划分为 0 个子数组,结果为 0),其他情况初始化为无穷大。

    • 优点:避免了递归的开销,时间复杂度更优。

两种方法的核心都是通过动态规划找到最优划分方案,区别在于递归和迭代的实现方式。以及如果用迭代对于剪枝的优化效果会更明显。

实际操作的过程,不熟悉的同学可以先递归,对于无法通过的题目可以尝试修改为动态规划。等熟练后建议大家数据规模不大递归即可,数据规模稍微有点大,直接动态规划。

解法

方法一:记忆化递归

我们使用带记忆化的自顶向下方法来高效计算结果。

复杂度:

  • 时间复杂度:(O(n^2 \cdot k)),其中 (n) 是 nums 的长度。每个状态 (i, k) 需要 (O(n)) 时间计算,共有 (O(n \cdot k)) 个状态。

  • 空间复杂度:(O(n \cdot k)),用于记忆化缓存。

方法二:动态规划

自底向上的动态规划方法通过迭代构建解,避免了递归开销。

复杂度:

  • 时间复杂度:(O(n^2 \cdot k)),由于三重循环。

  • 空间复杂度:(O(n \cdot k)),用于 DP 表。

最后更新于

这有帮助吗?