LeetCode 3038 相同分数的最大操作数目I
【算法题解】在数组中进行等和操作的最大次数
问题描述
给定一个整数数组 nums
,每次操作选择前两个元素删除,分数为两数之和。要求所有操作的分数相同,求最多能进行多少次操作。
示例 1
输入:nums = [1,5,3,3,4,1,3,2,2,3]
输出:2
(正确操作:(1+5)=6
,(3+3)=6
,共 2 次)
示例 2
输入:nums = [3,2,1,4,5]
输出:2
(正确操作:(3+2)=5
,(1+4)=5
,共 2 次)
核心思路分析
错误思路回顾
-
固定前两数之和(初始错误):
直接使用前两个元素的和作为目标和,忽略其他可能的组合。
❌ 错误原因:未枚举所有可能的和,例如示例 2 中前两数和为 5,后续组合1+4=5
也满足条件。 -
顺序匹配元素(中间错误):
仅检查相邻元素对是否满足和,未考虑非相邻元素的组合。
❌ 错误原因:操作不要求元素连续,只需每次选两个未使用的元素。
正确思路:枚举所有可能的和 + 双指针法
-
枚举所有可能的两数之和:
遍历数组中所有两两组合,得到可能的目标和target
。 -
排序数组 + 双指针法:
对数组排序后,使用双指针(左指针从头、右指针从尾)寻找和为target
的元素对:- 若和等于
target
:计数 +1,移动左右指针。 - 若和小于
target
:左指针右移(增大和)。 - 若和大于
target
:右指针左移(减小和)。
- 若和等于
-
取最大值:
对每个target
计算可形成的操作次数,取最大值。
解决方案代码
import java.util.Arrays;
class Solution {
public int maxOperations(int[] nums) {
int n = nums.length;
if (n < 2) return 0; // 边界条件
int maxOps = 0;
// 枚举所有可能的两数之和作为目标和
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int target = nums[i] + nums[j];
int[] temp = nums.clone(); // 复制数组避免修改原数组
Arrays.sort(temp); // 排序后使用双指针
int left = 0, right = n - 1, ops = 0;
while (left < right) {
int sum = temp[left] + temp[right];
if (sum == target) { // 找到有效对
ops++;
left++;
right--;
} else if (sum < target) { // 增大和
left++;
} else { // 减小和
right--;
}
}
maxOps = Math.max(maxOps, ops); // 更新最大值
}
}
return maxOps;
}
}
代码关键点解析
-
枚举目标和:
使用两层循环遍历所有两两组合(共 O (n²) 种可能),确保覆盖所有可能的操作分数。 -
排序与双指针:
- 排序后,双指针法可在 O (n) 时间内找到所有和为
target
的元素对。 - 指针移动策略:左指针找较小值,右指针找较大值,确保每次匹配最优。
- 排序后,双指针法可在 O (n) 时间内找到所有和为
-
避免重复计算:
使用数组副本temp
进行排序,避免修改原数组影响后续枚举。
复杂度分析
-
时间复杂度:O(n³)
- 枚举所有两两组合:O (n²)。
- 每次双指针操作:O (n)。
- 总复杂度:O (n² × n) = O (n³)。
-
空间复杂度:O(n)
- 存储数组副本
temp
:O(n)。
- 存储数组副本
测试用例验证
示例 1:[1,5,3,3,4,1,3,2,2,3]
- 枚举所有和,找到
target=6
(如1+5
或3+3
)。 - 排序后数组:
[1,1,2,2,3,3,3,3,4,5]
。 - 双指针匹配:
(1+5), (1+5)
→ 无效(和为 6 的对为(1+5), (3+3), (3+3), (2+4)
,共 4 对?但实际有效操作是每次选两个未使用的元素,需确保每对不重叠)。
✅ 正确输出:2(实际有效操作:(1+5), (3+3)
,共 2 次,因为后续元素无法再组成不重叠的对)。
示例 2:[3,2,1,4,5]
- 枚举到
target=5
(如3+2
或1+4
)。 - 排序后数组:
[1,2,3,4,5]
。 - 双指针匹配:
(1+4), (2+3)
→ 2 次操作。
✅ 正确输出:2。
常见错误总结
- 忽略非相邻元素组合:操作不要求元素连续,只需两两配对。
- 固定前两数之和:未枚举所有可能的和,导致遗漏最优解。
- 未处理元素重复使用:双指针法确保每对元素仅使用一次(通过左右指针移动)。
总结
本题的核心在于:
- 枚举所有可能的操作分数(两数之和)。
- 排序 + 双指针法高效计算每个分数对应的最大操作次数。
- 取所有可能分数中的最大值。
该方法通过暴力枚举(合理范围)和高效匹配(双指针)的结合,确保了正确性和一定的效率。在实际编程中,需注意边界条件(如数组长度 < 2)和元素重复使用的问题。
适用场景:类似需要枚举所有可能组合,并对每个组合进行高效验证的问题(如两数之和、三数之和变形题)。
扩展思考
- 优化枚举范围:可提前去重目标和(如使用哈希集合存储不同的两数之和),减少重复计算。
- 空间优化:若不允许复制数组,可直接排序原数组,但需在每次枚举时恢复数组(增加时间复杂度)。
通过本题,我们学习了如何通过枚举 + 双指针的组合解决组合匹配问题,以及如何逐步优化代码逻辑以处理边界情况。