• [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

  • 相关阅读:
    shell 网络状态查询 ping curl telnet
    shell 命令 rz sz
    shell 命令之 jps
    Python 之 threading
    根据 MySQL 状态优化 ---- 4. 临时表
    根据 MySQL 状态优化 ---- 3. key_buffer_size
    根据 MySQL 状态优化 ---- 2. 连接数
    根据 MySQL 状态优化 ---- 1. 慢查询
    Linux 服务器的网络配置
    Linux 服务器的网络配置
  • 原文地址:https://www.cnblogs.com/hellojamest/p/16491916.html
Copyright © 2020-2023  润新知