相同分数的最大操作数目II

2024-06-08

题目:

给你一个整数数组 nums ,如果 nums 至少 包含 2 个元素,你可以执行以下操作中的 任意 一个:

  • 选择 nums 中最前面两个元素并且删除它们。
  • 选择 nums 中最后两个元素并且删除它们。
  • 选择 nums 中第一个和最后一个元素并且删除它们。

一次操作的 分数 是被删除元素的和。在确保 所有操作分数相同 的前提下,请你求出 最多 能进行多少次操作。请你返回按照上述要求 最多 可以进行的操作次数。

示例 1:

输入:nums = [3,2,1,2,3,4]
输出:3
解释:我们执行以下操作:
- 删除前两个元素,分数为 3 + 2 = 5 ,nums = [1,2,3,4] 。
- 删除第一个元素和最后一个元素,分数为 1 + 4 = 5 ,nums = [2,3] 。
- 删除第一个元素和最后一个元素,分数为 2 + 3 = 5 ,nums = [] 。
由于 nums 为空,我们无法继续进行任何操作。

示例 2:

输入:nums = [3,2,6,1,4]
输出:2
解释:我们执行以下操作:
- 删除前两个元素,分数为 3 + 2 = 5 ,nums = [6,1,4] 。
- 删除最后两个元素,分数为 1 + 4 = 5 ,nums = [6] 。
至多进行 2 次操作。

提示:

  • 2 <= nums.length <= 2000
  • 1 <= nums[i] <= 1000

思路:

这题咋一看很难,是因为首先它的操作有三个(不只一个就说明要记录结果并比较了);其次是因为确定了分数后,每一次删减元素都有三种选择,必须记录结果并取最大值。所以这么一分析,做法肯定是动态规划。

首先我们要抽象问题,要求取得相同分数的最大操作次数,我们第一步就是确定分数,这里分数只有三种可能。第一:nums[0] + nums[1] 第二:nums[0] + nums[n - 1] 第三:nums[n - 1] + nums[n - 2]
确定好了分数target之后,我们再去动态规划求取在该分数下的最大操作次数

1.确定dp数组含义
memo[i][j]代表从区间[i, j]中进行删减元素可以进行的最大操作次数

2.确定递推公式
我们用函数dfs(i, j)来获取区间[i, j]的最大操作次数
对于区间[i, j]来说,它的结果可以由三种可能性确定:
	nums[i] + nums[i + 1] == target, memo[i][j] = dfs(i + 2, j) + 1
	nums[j - 1] + nums[j - 2] == target, memo[i][j] = dfs(i, j - 2) + 1
	nums[i] + nums[j] == target, memo[i][j] = dfs(i + 1, j - 1) + 1
我们取三个的最大值即是memo[i][j]

3.确定遍历顺序
其实没有遍历顺序,最初的入口是dfs(0, n - 1)

4.确定初始化条件
由于要取最大值,所以memo[i][j] = -1

说一个点,这题看似动态规划,但其实核心点还是在于深度优先搜索。
在确定好分数之后,其实就是构建树的过程。每次从三棵子树中选择一个最大的进行搜索

代码:

class Solution {
public:
    int maxOperations(vector<int>& nums) {
        int n = nums.size();
        int memo[n][n];
        auto helper = [&](int i, int j, int target) -> int{
            memset(memo, -1, sizeof(memo));
            function<int(int, int)> dfs = [&](int i, int j) -> int{
                //区间不合理
                if (i >= j) { return 0; }
                //已经访问过,没必要再访问
                if (memo[i][j] != -1) { return memo[i][j]; }
                int ans = 0;
                if (nums[i] + nums[i + 1] == target) {
                    ans = max(ans, 1 + dfs(i + 2, j));
                }
                if (nums[i] + nums[j] == target) {
                    ans = max(ans, 1 + dfs(i + 1, j - 1));
                }
                if (nums[j - 1] + nums[j] == target) {
                    ans = max(ans, 1 + dfs(i, j - 2));
                }
                memo[i][j] = ans;
                return ans;
            };
            return dfs(i, j);
        };
        int res = 0;
        res = max(res, helper(0, n - 1, nums[0] + nums[n - 1]));
        res = max(res, helper(0, n - 1, nums[0] +nums[1]));
        res = max(res, helper(0, n - 1, nums[n - 2] + nums[n - 1]));
        return res;
    }
};