LeetCode.302 场周赛___02_6164. 数位和相等数对的最大和___哈希 + 增强预处理 + 自定义优先队列

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中出现过:

  1. 出现过,则根据数位和key拿到对应的value,记着判断其内部优先队列是否满,若未满,则根据最大优先队列思想,插入合适的位置;若已满,则判断和队列里的两个元素的大小关系,进行合适的操作,使得能够维护最大优先队列即可。
  2. 没出现过,则直接创建队列,将此元素加入队列中,充当此数位和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;
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值