• 统计一个数组中好对子的数目


    1814. 统计一个数组中好对子的数目

    题目

    给你一个数组 nums ,数组中只包含非负整数。定义 rev(x) 的值为将整数 x 各个数字位反转得到的结果。比方说 rev(123) = 321 , rev(120) = 21 。我们称满足下面条件的下标对 (i, j) 是 好的 :

    0 <= i < j < nums.length
    nums[i] + rev(nums[j]) == nums[j] + rev(nums[i])
    请你返回好下标对的数目。由于结果可能会很大,请将结果对 109 + 7 取余 后返回。

    提示:

    1 <= nums.length <= 105
    0 <= nums[i] <= 109

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/count-nice-pairs-in-an-array
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解析

    分析

    先得到nums对应的rev数组。根据等式nums[i] + rev(nums[j]) == nums[j] + rev(nums[i])可以得到nums[i] - rev(nums[i]) == nums[j] - rev(nums[j])。所以我们求一个diff数组,其中diff[i]=nums[i]-rev[i]

    问题转化为:
    找到i,j对,i<j,且diff[i]==diff[j]。假设diff为val的有k个,则这样的对数有k*(k-1)/2个。对所有不同diff的对数求和,就能得到所有的满足条件的下标对数。

    这道题需要注意的是溢出问题。由于n<=105,所以k*(k-1)可能是long。但是rev和diff是不会溢出,因为nums[i]<109,而int最大超过2x1010。

    代码

    class Solution {
        int MOD=1000000007;
        public int countNicePairs(int[] nums) {
            int[] revs=getRevs(nums);
            // System.out.println(Arrays.toString(revs)); 
            int[] diff=getDiff(nums,revs);
            // System.out.println(Arrays.toString(diff)); 
            Map<Integer,Integer> frq=groupByDiff(diff);
            
            // System.out.println(frq); 
            return getCount(frq);
        }
        
        private int getCount(Map<Integer,Integer> frq){
            int sum=0;
            for(int f:frq.values()){
                long k=f;
                sum+=((k*(k-1))>>1)%MOD;
                sum%=MOD;
            }      
            return sum;
        }
        
        private Map<Integer,Integer> groupByDiff(int[] diff){
            Map<Integer,Integer> res=new HashMap<Integer,Integer>();
            for(int val:diff){
                int cnt=0;
                if(res.containsKey(val)){
                    cnt=res.get(val);
                }
                res.put(val,cnt+1);
            }
            return res;
        }
        private int[] getDiff(int[] nums,int[] revs){
            int n=nums.length;
            int[] res=new int[n];
            for(int i=0;i<n;i++){
                res[i]=nums[i]-revs[i];//溢出?
            }
            return res;
        }
        
        private int[] getRevs(int[] nums){
            int n=nums.length;
            int[] res=new int[n];
            for(int i=0;i<n;i++){
                res[i]=getR(nums[i]);
            }
            return res;
        }
        
        private int getR(int val){
            int res=0;
            while(val!=0){
                res*=10;
                int mod=val%10;
                val/=10;
                res+=mod;
            }
            return res;
        }
    }
    

    复杂度分析

    空间:O(N)用于放数组和map(其实可以优化成diff就用原来的rev空间)
    时间:O(N)。

    优秀题解

    得到diff数组,按照从小到大排序。双指针i和j,j一直走到和i位置的值不相等,求得k并求和,然后更新i=j。

    核心代码:

    Arrays.sort(revNums);
    int ans = 0;
    int mod = 1_000_000_007;
    int i = 0;
     for (int j = 0; j < revNums.length; ++j) {
        if (revNums[j] != revNums[i]) {
            long n = (long)(j - i) * (long)(j - i - 1) >> 1;
            n %= mod;
            ans += (int)n;
            if (ans > mod) ans -= mod;
            i = j;
        }
    }
    if (i != revNums.length - 1) {
        int j = revNums.length;
        long n = (long)(j - i) * (long)(j - i - 1) >> 1;
        n %= mod;
        ans += (int)n;
        if (ans > mod) ans -= mod;
    }
    

    时间:O(NlogN)
    空间:O(N)放rev数组

  • 相关阅读:
    Android架构初探
    TinyPNG---一个压缩PNG的神站
    Android添加全屏启动画面
    如何唯一的标识一台Android设备?
    获取Android设备唯一标识码
    Android系统资源图标android.R.drawable
    Android中使用adb访问SQLite的方法
    Java 对字符串数据进行MD5/SHA1哈希散列运算
    关于Android中EditText自动获取焦点并弹出键盘的相关设置
    EditText自动换行显示内容
  • 原文地址:https://www.cnblogs.com/FannyChung/p/tong-ji-yi-ge-shu-zu-zhong-hao-dui-zi-de-shu-mu.html
Copyright © 2020-2023  润新知