6164. 数位和相等数对的最大和
给你一个下标从 0 开始的数组 nums ,数组中的元素都是 正 整数。请你选出两个下标 i 和 j(i != j),且 nums[i] 的数位和 与 nums[j] 的数位和相等。
请你找出所有满足条件的下标 i 和 j ,找出并返回 nums[i] + nums[j] 可以得到的 最大值 。
示例 1:
输入:nums = [18,43,36,13,7]
输出:54
解释:满足条件的数对 (i, j) 为:
- (0, 2) ,两个数字的数位和都是 9 ,相加得到 18 + 36 = 54 。
- (1, 4) ,两个数字的数位和都是 7 ,相加得到 43 + 7 = 50 。
所以可以获得的最大和是 54 。
示例 2:
输入:nums = [10,12,19,14]
输出:-1
解释:不存在满足条件的数对,返回 -1 。
提示:
- 1 <= nums.length <= 105
- 1 <= nums[i] <= 109
Solution1(直接暴力):
- 我们直接暴力枚举i,j ,接着对nums[i],nums[j]分别求数位和,一旦符合即可;
Code1:
class Solution {
public int maximumSum(int[] nums) {
int max = Integer.MIN_VALUE;
int len = nums.length;
for(int i=0;i<len;i++){
for(int j=i+1;j<len;j++){
//因为(0,2)和(2,0)是一样的这里,所以j从i+1开始即可
//且在这里求数位和会导致(0,2),(0,4)的0下标的数位和会重复计算,所以我们应该预处理
if(cal(nums[i],nums[j])){
max = Math.max(max,nums[i] + nums[j]);
}
}
}
return max == Integer.MIN_VALUE ? -1 : max;
}
public boolean cal(int i,int j){
int sum1 = 0;
int sum2 = 0;
while(i > 0){
sum1 += (i % 10);
i /= 10;
}
while(j > 0){
sum2 += (j % 10);
j /= 10;
}
if(sum1 == sum2){
return true;
}
return false;
}
}
Solution2(简单预处理):
- 我们发现如果在遍历i,j 的时候再进行求数位和的操作会比较浪费时间,因为在这里求数位和会导致(0,2),(0,4)的0下标的数位和会重复计算,所以我们应该进行预处理;
Code2:
/* 空间换时间,先预处理数位和 */
class Solution {
public int maximumSum(int[] nums) {
int max = Integer.MIN_VALUE;
int len = nums.length;
int[] bef = new int[len];
for(int i=0;i<len;i++){
bef[i] = cal(nums[i]);
}
for(int i=0;i<len;i++){
for(int j=i+1;j<len;j++){
if(bef[i] == bef[j]){
max = Math.max(max,nums[i] + nums[j]);
}
}
}
return max == Integer.MIN_VALUE ? -1 : max;
}
public int cal(int i){
int sum1 = 0;
while(i > 0){
sum1 += (i % 10);
i /= 10;
}
return sum1;
}
}
Solution3(哈希 + 增强预处理 + 自定义优先队列):
由于我们不在乎数位和的大小,只在乎找到同一数位和的两个元素加起来和最大,因此我们可以对可以产生的每一种数位和都进行提前预处理,使得每一个产生的数位和直接对应一个长度为2的最大优先队列,其包含了在这个数位和的情况下,所能找到的最大的两个数nums[i]和nums[j],因此在预处理完毕后,我们直接遍历各种数位和,找出最大的队列元素和即可。
为实现上述预处理,我们可以建立一个哈希表map,接着遍历nums,对其每一个元素求数位和,且判断此数位和是否在map中出现过:
出现过
,则根据数位和key拿到对应的value,记着判断其内部优先队列是否满,若未满,则根据最大优先队列思想,插入合适的位置;若已满,则判断和队列里的两个元素的大小关系,进行合适的操作,使得能够维护最大优先队列即可。没出现过
,则直接创建队列,将此元素加入队列中,充当此数位和key的value。
Code3:
/* 哈希 + 增强预处理 + 自定义优先队列 */
class Solution {
public int maximumSum(int[] nums) {
int max = Integer.MIN_VALUE;
int len = nums.length;
Map<Integer,List<Integer>> map = new HashMap<>();
for(int i=0;i<len;i++){
int temp = cal(nums[i]);
if(map.containsKey(temp)){
List<Integer> list = map.get(temp);
if(list.size() == 2){
if(nums[i] > nums[list.get(0)]){
list.set(1,list.get(0));
list.set(0,i);
}
else if(nums[i] > nums[list.get(1)]){
list.set(1,i);
}
}
else{
if(nums[list.get(0)] > nums[i]){
list.add(i);
}
else{
int t = list.get(0);
list.set(0,i);
list.add(t);
}
}
}
else{
List<Integer> list = new ArrayList<>();
list.add(i);
map.put(temp,list);
}
}
for(Map.Entry<Integer, List<Integer>> entry : map.entrySet()){
List<Integer> list = entry.getValue();
if(list.size() != 2)
continue;
max = Math.max(max,nums[list.get(0)] + nums[list.get(1)]);
}
return max == Integer.MIN_VALUE ? -1 : max;
}
public int cal(int i){
int sum1 = 0;
while(i > 0){
sum1 += (i % 10);
i /= 10;
}
return sum1;
}
}