1. 问题背景与理解
今天我们要讨论的是LeetCode第2342题"数位和相等的最大和"。这是一道非常适合算法初学者练习数组和哈希表应用的题目。题目描述如下:
给定一个整数数组nums,我们需要找到两个不同的索引i和j,使得nums[i]和nums[j]的数位和相等,并且nums[i]+nums[j]的值是所有满足这个条件的数对中最大的。如果不存在这样的数对,则返回-1。
首先,我们需要明确几个关键概念:
-
数位和:一个数字的数位和是指它的每一位数字相加的总和。例如,数字123的数位和是1+2+3=6。
-
最大和:我们需要在所有满足数位和相等的数对中,找到和最大的那一对。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路分析
2.1 暴力解法与优化方向
最直观的解法是使用双重循环遍历所有可能的数对,计算每对数的数位和,然后找出满足条件且和最大的那一对。这种方法的时间复杂度是O(n²),对于较大的数组来说效率很低。
我们需要寻找更高效的解法。观察题目特点,我们可以发现:
- 我们只关心数位和相同的数字
- 对于每个数位和,我们只需要保留最大的两个数字(因为它们的和会是最大的)
这提示我们可以使用哈希表来存储数位和对应的数字,从而优化时间复杂度。
2.2 哈希表的使用策略
我们可以创建一个哈希表,其中键是数位和,值是该数位和对应的数字列表。具体步骤如下:
- 遍历数组中的每个数字
- 计算当前数字的数位和
- 将数字存入哈希表中对应的数位和键下
- 对于每个数位和,只保留最大的两个数字(因为我们只需要最大的和)
- 最后遍历哈希表,计算每个数位和对应的两个最大数字的和,找出最大的那个
这种方法的时间复杂度是O(n),因为我们只需要遍历数组一次,然后遍历哈希表一次。
3. 详细实现步骤
3.1 计算数位和的函数
首先,我们需要一个辅助函数来计算数字的数位和:
python复制def digit_sum(num):
total = 0
while num > 0:
total += num % 10
num = num // 10
return total
这个函数通过不断取模和整除来获取数字的每一位并求和。
3.2 主函数实现
下面是主函数的实现步骤:
python复制def maximumSum(nums):
# 创建哈希表存储数位和对应的数字
sum_dict = {}
# 遍历数组中的每个数字
for num in nums:
# 计算数位和
current_sum = digit_sum(num)
# 将数字存入哈希表
if current_sum not in sum_dict:
sum_dict[current_sum] = []
sum_dict[current_sum].append(num)
max_total = -1
# 遍历哈希表中的每个数位和
for key in sum_dict:
# 如果该数位和对应至少两个数字
if len(sum_dict[key]) >= 2:
# 排序并取最大的两个
sorted_nums = sorted(sum_dict[key], reverse=True)
current_total = sorted_nums[0] + sorted_nums[1]
# 更新最大和
if current_total > max_total:
max_total = current_total
return max_total
3.3 优化空间
上述实现中,我们在最后对每个数位和对应的数字列表进行了排序。实际上,我们可以在填充哈希表时就维护每个数位和对应的最大两个数字,这样可以避免最后的排序操作,进一步提高效率。
优化后的实现:
python复制def maximumSum(nums):
sum_dict = {}
for num in nums:
current_sum = digit_sum(num)
if current_sum not in sum_dict:
sum_dict[current_sum] = []
# 维护最多两个最大的数字
if len(sum_dict[current_sum]) < 2:
sum_dict[current_sum].append(num)
else:
# 找到三个数中最小的替换掉
min_num = min(sum_dict[current_sum])
if num > min_num:
sum_dict[current_sum].remove(min_num)
sum_dict[current_sum].append(num)
max_total = -1
for key in sum_dict:
if len(sum_dict[key]) == 2:
current_total = sum(sum_dict[key])
if current_total > max_total:
max_total = current_total
return max_total
4. 复杂度分析
让我们分析一下优化后算法的时间和空间复杂度:
-
时间复杂度:O(n * d),其中n是数组长度,d是数字的平均位数。因为我们需要遍历数组一次,并对每个数字计算其数位和。
-
空间复杂度:O(n),最坏情况下每个数字的数位和都不同,哈希表需要存储n个键值对。
5. 边界条件与测试用例
5.1 常见测试用例
python复制# 示例1
nums = [18,43,36,13,7]
print(maximumSum(nums)) # 输出:54 (18+36)
# 示例2
nums = [10,12,19,14]
print(maximumSum(nums)) # 输出:-1 (没有数位和相同的数对)
# 示例3
nums = [123, 321, 456, 654] # 数位和都是6
print(maximumSum(nums)) # 输出:975 (321+654)
5.2 特殊边界情况
- 空数组或单元素数组:应该返回-1
- 所有数字的数位和都不同:应该返回-1
- 多个数位和相同的数对:应该返回最大的和
- 负数处理:题目中nums[i]是正整数,所以不需要考虑
6. 实际应用与扩展
6.1 实际应用场景
这类问题在实际中有多种应用:
- 数据分析:寻找具有某些共同特征的数据对
- 密码学:寻找具有特定属性的数字组合
- 游戏开发:设计基于数字属性的匹配机制
6.2 类似题目扩展
掌握了这道题的解法后,可以尝试解决以下类似题目:
- 找出所有数位和相同的数对
- 找出数位和相同且乘积最大的数对
- 找出数位和相同且差最小的数对
7. 常见错误与调试技巧
7.1 初学者常见错误
- 忘记处理没有满足条件数对的情况(应该返回-1)
- 在维护最大两个数字时逻辑错误
- 数位和计算错误,特别是对于包含0的数字
7.2 调试技巧
- 打印中间结果:在计算数位和时打印出来检查
- 使用小规模测试用例:先在小数组上验证逻辑
- 边界测试:专门测试空数组、单元素数组等情况
8. 算法优化进阶
8.1 并行计算优化
对于非常大的数组,可以考虑并行计算:
- 将数组分割成多个部分
- 在不同线程/进程中计算各部分的结果
- 合并结果
8.2 空间优化
如果内存受限,可以:
- 不存储所有数字,只维护每个数位和对应的最大两个数字
- 使用更紧凑的数据结构
9. 不同语言实现对比
9.1 Python实现特点
Python的字典使用方便,但性能不如一些编译型语言。可以使用defaultdict简化代码:
python复制from collections import defaultdict
def maximumSum(nums):
sum_dict = defaultdict(list)
# 其余代码相同
9.2 Java实现
Java可以使用HashMap,需要注意类型声明和更繁琐的语法:
java复制import java.util.*;
public class Solution {
public int maximumSum(int[] nums) {
Map<Integer, List<Integer>> sumMap = new HashMap<>();
// 实现逻辑类似
}
private int digitSum(int num) {
// 数位和计算
}
}
10. 学习建议与资源推荐
10.1 学习路径建议
- 先掌握基础的数据结构:数组、哈希表
- 练习简单的算法问题:求和、查找等
- 逐步挑战更复杂的问题
10.2 推荐资源
- LeetCode题库:从简单题开始练习
- 《算法导论》:经典算法教材
- 在线课程:如Coursera上的算法专项课程
这道题目很好地结合了数组操作和哈希表的使用,是算法学习中的一个典型例题。通过解决这个问题,可以加深对哈希表应用场景的理解,并学会如何将O(n²)的暴力解法优化为O(n)的高效解法。
