携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情
题目链接:2321. 拼接数组的最大分数
题目描述
给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,长度都是 n 。
你可以选择两个整数 left 和 right ,其中 0 <= left <= right < n ,接着 交换 两个子数组 nums1[left...right] 和 nums2[left...right] 。
- 例如,设
nums1 = [1,2,3,4,5]和nums2 = [11,12,13,14,15],整数选择left = 1和right = 2,那么nums1会变为[1,12,13,4,5]而nums2会变为[11,2,3,14,15]。 你可以选择执行上述操作 一次 或不执行任何操作。
数组的 分数 取 sum(nums1) 和 sum(nums2) 中的最大值,其中 sum(arr) 是数组 arr 中所有元素之和。
返回 可能的最大分数 。
子数组 是数组中连续的一个元素序列。arr[left...right] 表示子数组包含 nums 中下标 left 和 right 之间的元素(含 下标 left 和 right 对应元素)。
提示:
示例 1:
输入:nums1 = [60,60,60], nums2 = [10,90,10]
输出:210
解释:选择 left = 1 和 right = 1 ,得到 nums1 = [60,90,60] 和 nums2 = [10,60,10] 。
分数为 max(sum(nums1), sum(nums2)) = max(210, 80) = 210 。
示例 2:
输入:nums1 = [20,40,20,70,30], nums2 = [50,20,50,40,20]
输出:220
解释:选择 left = 3 和 right = 4 ,得到 nums1 = [20,40,20,40,20] 和 nums2 = [50,20,50,70,30] 。
分数为 max(sum(nums1), sum(nums2)) = max(140, 220) = 220 。
示例 3:
输入:nums1 = [7,11,13], nums2 = [1,1,1]
输出:31
解释:选择不交换任何子数组。
分数为 max(sum(nums1), sum(nums2)) = max(31, 3) = 31 。
整理题意
题目给定两个长度相同的数组,我们可以对这两个数组进行一次操作(或者不操作),使得两个数组中任意一个的数组元素和最大。可执行的操作为选取两个数组相同下标且连续的子数组进行交换。
解题思路分析
- 首先观察题目数据范围,数组长度在 以内,暴力枚举所有连续子数组会
TLE超时。 我们设两数组交换的连续子数组区间为[left, right],那么对于数组nums1来说,设nums1在未交换之前的数组和为sum1,其交换后数组和为: sum1 - (nums1[left] + ... + nums1[right]) + (nums2[left] + ... + nums2[right])我们对上式子进行整理,合并nums1和nums2相同下标部分,整理得:sum1 + (nums2[left] - nums1[left]) + ... + (nums2[right] - nums1[right])我们令diff1[i] = nums2[i] - nums1[i]可得:sum1 + diff1[left] + ... + diff1[right]观察这个式子可知,题目要求sum1 + diff1[left] + ... + diff1[right]的最大值,因为sum1为定值,那么即求diff1[left] + ... + diff1[right]的最大值,我们可以通过遍历求得diff1数组。
那么问题进而转换为:求 diff1 数组的 最大连续子数组 ,即可求得交换数组后 nums1 数组和的最大值。
我们同理可得 diff2 数组以及 diff2 数组的 最大连续子数组 ,进而得知交换数组后 nums2 数组和的最大值。
那么答案就是二者取最大值即可。
求一个数组的 最大连续子数组 问题为 53. 最大子数组和,具体方法为使用动态规划以时间复杂度为 递推求得。
具体实现
由于该问题可以通过相同的方法求得 diff1 和 diff2 的最大连续子数组和,进而求得交换数组后 nums1 和 nums2 数组和的最大值,那么我们可以将代码优化为一个函数,该函数可以求得数组交换后的数组和最大值。那么在解决相同问题时就可以进行复用。
在求 diff 数组的最大连续子数组和时利用滚动数组思想进行空间优化。
复杂度分析
- 时间复杂度:,n 为数组
nums1和nums2中的元素个数,通过一次遍历可求得数组diff1和diff2,再分别遍历数组diff1和diff2,求得交换数组后nums1和nums2数组和的最大值。 - 空间复杂度:。利用滚动数组思想将空间复杂度降低为 。
代码实现
class Solution {
private:
//求得交换数组后的最大数组和(对于该函数的nums1来说的最大数组和)
int f(vector<int>& nums1, vector<int>& nums2){
//求原数组 nums1 的数组和
int sum = 0;
int n = nums1.size();
//求 diff 数组的连续子数组和的最大值,利用滚动数组思想优化
int dp = 0, res = 0;
for(int i = 0; i < n; i++){
sum += nums1[i];
int diff = nums2[i] - nums1[i];
dp = max(dp + diff, diff);
res = max(res, dp);
}
return sum + res;
}
public:
int maximumsSplicedArray(vector<int>& nums1, vector<int>& nums2) {
return max(f(nums1, nums2), f(nums2, nums1));
}
};
总结
- 该题的核心为 求数组的最大连续子数组和,只是题目将该其隐藏的比较好,需要我们将问题进行转换。
- 在面临同理可得这一结论时,我们可以考虑代码的复用性,将同理部分代码进行封装写成函数,在求相同问题时可以进行复用。
- 本文对 求数组的最大连续子数组和 没有详细讲述,仅进行了方法概括,因为本题核心是如何将问题转换为求数组的最大连续子数组和。详细求解 求数组的最大连续子数组和 的方法可以在 53. 最大子数组和 中进行查看。
- 测试结果:
结束语
无论做什么事,都不可能一蹴而就。阅读书籍,没有立竿见影的好处,却会给你广阔的视野;培养好习惯,过程并不容易,却能让你持久获益。别因为短期看不到回报就拒绝努力,当下的每一点付出,都会在未来助你成为更耀眼的自己。新的一天,加油!