[Leetcode Weekly Contest]302

链接:LeetCode

[Leetcode]2341. 数组能形成多少数对

给你一个下标从 0 开始的整数数组 nums 。在一步操作中,你可以执行以下步骤:

  • 从 nums 选出 两个 相等的 整数
  • 从 nums 中移除这两个整数,形成一个 数对
    请你在 nums 上多次执行此操作直到无法继续执行。
    返回一个下标从 0 开始、长度为 2 的整数数组 answer 作为答案,其中 answer[0] 是形成的数对数目,answer[1] 是对 nums 尽可能执行上述操作后剩下的整数数目。

哈希。循环模拟,统计每个元素的出现次数,两两一对,得到对数。

class Solution {
    public int[] numberOfPairs(int[] nums) {
        HashMap<Integer, Integer> hash = new HashMap<>();
        for(var num:nums) hash.put(num, hash.getOrDefault(num, 0)+1);
        int[] res = new int[2];
        for(var entry:hash.entrySet()) {
            int value = entry.getValue();
            if((value & 1) != 0) res[1] ++;
            res[0] += value/2;
        }
        return res;
    }
}

[Leetcode]2342. 数位和相等数对的最大和

给你一个下标从 0 开始的数组 nums ,数组中的元素都是 正 整数。请你选出两个下标 i 和 j(i != j),且 nums[i] 的数位和 与 nums[j] 的数位和相等。
请你找出所有满足条件的下标 i 和 j ,找出并返回 nums[i] + nums[j] 可以得到的 最大值 。

哈希表 + 一次遍历

class Solution {
    public int maximumSum(int[] nums) {
        HashMap<Integer, MyClass> hash = new HashMap<>();
        for(var num: nums) {
            int key = 0, raw = num;
            while(num!=0) {
                key += num%10;
                num = num/10;
            }
            if(!hash.containsKey(key)) {
                MyClass mc = new MyClass();
                mc.MxVal = raw;
                hash.put(key, mc);
            } else {
                MyClass mc = hash.get(key);
                if(raw > mc.MxVal) {
                    mc.SecMxVal = mc.MxVal;
                    mc.MxVal = raw;
                }
                else if(raw > mc.SecMxVal) {
                    mc.SecMxVal = raw;
                }
                hash.put(key, mc);
            }
        }
        int res = -1;
        for(var entry:hash.entrySet()) {
            MyClass mc = entry.getValue();
            if(mc.MxVal!=-1 && mc.SecMxVal!=-1) {
                res = Math.max(res, mc.MxVal+mc.SecMxVal);
            }
        }
        return res;
    }
}

class MyClass {
    int MxVal = -1;
    int SecMxVal = -1;
}

[Leetcode]2343. 裁剪数字后查询第 K 小的数字

给你一个下标从 0 开始的字符串数组 nums ,其中每个字符串 长度相等 且只包含数字。
再给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [ki, trimi] 。对于每个 queries[i] ,你需要:

  • 将 nums 中每个数字 裁剪 到剩下 最右边 trimi 个数位。
  • 在裁剪过后的数字中,找到 nums 中第 ki 小数字对应的 下标 。如果两个裁剪后数字一样大,那么下标 更小 的数字视为更小的数字。
  • 将 nums 中每个数字恢复到原本字符串。

请你返回一个长度与 queries 相等的数组 answer,其中 answer[i]是第 i 次查询的结果。

提示:

  • 裁剪到剩下 x 个数位的意思是不断删除最左边的数位,直到剩下 x 个数位。
  • nums 中的字符串可能会有前导 0 。

基数排序。询问其实问的就是基数排序第 trim 轮中的第 k 小值。复杂度就是基数排序的 \(\mathcal{O}(nm)\),其中 \(m\) 是 nums 中每个字符串的长度。

class Solution {
    public int[] smallestTrimmedNumbers(String[] nums, int[][] queries) {
        int n = nums.length, m = nums[0].length();
        int[][] radix = new int[m+1][n];
        for(int i=0;i<n;++i) radix[0][i] = i;
        for(int i=1;i<=m;++i) {
            ArrayList<Integer>[] bucket = new ArrayList[10];
            for(int j=0;j<10;++j) bucket[j] = new ArrayList<Integer>();
            for(var idx:radix[i-1]) bucket[(int)(nums[idx].charAt(m-i) - '0')].add(idx);
            int cnt = 0;
            for(int j=0;j<10;++j) {
                for(var x:bucket[j]) {
                    radix[i][cnt] = x;
                    cnt ++;
                }
            }
        }
        int[] res = new int[queries.length];
        int i = 0;
        for(var query:queries) {
            res[i] = radix[query[1]][query[0]-1];
            i ++;
        }
        return res;
    }
}

[Leetcode]2344. 使数组可以被整除的最少删除次数

给你两个正整数数组 nums 和 numsDivide 。你可以从 nums 中删除任意数目的元素。
请你返回使 nums 中 最小 元素可以整除 numsDivide 中所有元素的 最少 删除次数。如果无法得到这样的元素,返回 -1 。
如果 y % x == 0 ,那么我们说整数 x 整除 y 。

只有 numsDivide 的最大公约数的因数才能整除 numsDivide 中的所有数。设该最大公约数为 \(g\),问题变为:
从 nums 中删除尽量少的元素,使得 nums 中的最小值可以整除 g。
若当前 nums 不满足条件,我们必须删除 nums 中的最小值。否则 nums 中的最小值一直不变,那么条件也一直不可能达成。
因此我们将 nums 排序,每次删掉 nums 中第一个数,直到第一个数可以整除 g 为止。复杂度 \(\mathcal{O}(n \log A + n \log n)\),其中 A 是 numsDivide 中的最大元素。

class Solution {
    public int minOperations(int[] nums, int[] numsDivide) {
        int minNum = Integer.MAX_VALUE;
        for(var num:numsDivide) {
            minNum = Math.min(minNum, num);
        }
        int val = 0;
        for(var num:numsDivide) {
            val = gcd(num, val);
        }
        Arrays.sort(nums);
        for(int i=0;i<nums.length;++i) {
            if(val % nums[i] == 0) return i;
        }
        return -1;
    }

    public int gcd(int p, int q) {
        if(q==0) return p;
        return gcd(q, p%q);
    }
}

参考:LeetCode

posted @ 2022-07-18 20:49  Jamest  阅读(41)  评论(0编辑  收藏  举报