📌  相关文章
📜  通过重复从串联为 3 的倍数的对中删除元素来最大化数组的总和(1)

📅  最后修改于: 2023-12-03 15:28:28.049000             🧑  作者: Mango

通过重复从串联为 3 的倍数的对中删除元素来最大化数组的总和

这是一道经典的动态规划问题,可以用类似于背包问题的思路来解决。

问题描述

给定一个包含 n 个非负整数的数组 nums,要求从 nums 中选取尽可能多的数,并删除其中的一些元素,使得剩下的数的下标可以被 3 整除,最终需要使得被选中的数的总和最大。

解决方案

在解决该问题时要考虑以下两个因素:

  • 如何选取数并删除不必要的元素。
  • 如何保证被选中的数的下标可以被 3 整除,并最终使得其总和最大。

首先,我们可以定义一个数组 dp,其中 dp[i] 表示前 i 个数中元素下标可以被 3 整除的最大和。

对于第一个因素,我们可以先将 nums 数组按从大到小排序,然后从左到右依次遍历,并判断删除当前元素后是否可以使当前下标被 3 整除。如果可以,则将该元素的值加入 dp 数组中,否则 dp[i] 的值与 dp[i-1] 相等。具体实现如下:

sort(nums.begin(), nums.end(), greater<int>());
for (int i = 0; i < n; ++i) {
    if (i % 3 == 0) {
        dp[i] = nums[i] + dp[i-1];
    } else {
        dp[i] = dp[i-1];
    }
}

对于第二个因素,我们需要注意到当一个数被选中时,它的下一个元素和下下个元素也必须被删除。为了处理这个问题,我们可以采用分组思想,即将下标分为若干个组,每个组包含 3 个元素。如果第一个元素被选中,则需要删除第二个和第三个元素,因此将这三个元素看作一个整体,将它们两两相邻地放在一个组中。同样地,对于每个 i%3==1 的元素也需要将其及其后面的两个元素放在一个组中。最终,我们只需要保证在选取数的同时,必须选择所有在当前组中的元素。

具体实现如下:

int ans = 0;
for (int i = 0; i < n; i += 3) {
    ans += dp[i];
}
return ans;
完整代码
int maxSum(vector<int>& nums) {
    int n = nums.size();
    vector<int> dp(n);
    sort(nums.begin(), nums.end(), greater<int>());
    for (int i = 0; i < n; ++i) {
        if (i % 3 == 0) {
            dp[i] = nums[i] + dp[i-1];
        } else {
            dp[i] = dp[i-1];
        }
    }
    int ans = 0;
    for (int i = 0; i < n; i += 3) {
        ans += dp[i];
    }
    return ans;
}
总结

此题是一道典型的动态规划问题,通过分析问题并考虑两个因素,我们可以得出一个简单且高效的解决方案。