3153.所有数对中数位不同之和

目标

你有一个数组 nums ,它只包含 正 整数,所有正整数的数位长度都 相同 。

两个整数的 数位不同 指的是两个整数 相同 位置上不同数字的数目。

请你返回 nums 中 所有 整数对里,数位不同之和。

示例 1:

输入:nums = [13,23,12]
输出:4
解释:
计算过程如下:
- 13 和 23 的数位不同为 1 。
- 13 和 12 的数位不同为 1 。
- 23 和 12 的数位不同为 2 。
所以所有整数数对的数位不同之和为 1 + 1 + 2 = 4 。

示例 2:

输入:nums = [10,10,10,10]
输出:0
解释:
数组中所有整数都相同,所以所有整数数对的数位不同之和为 0 。

说明:

  • 2 <= nums.length <= 10^5
  • 1 <= nums[i] < 10^9
  • nums 中的整数都有相同的数位长度。

思路

有一个数组其元素的数位长度相同,针对数组中所有可能的数对组合(即任选两个元素),比较其数位不同的个数并累加求和。

C(n,2) = n(n-1)/2 时间复杂度为 O(n^2),再加上数位比较,暴力枚举会超时。

考虑到所有元素的数位 digitLength 相同,那么可以统计所有元素该位上数字出现次数,时间复杂度为 O(digitLength*n)。然后逐数位比较,即在 0~9 之间组合,组合数等于对应数位数字出现次数的乘积。外层数位循环最大为10(可以忽略掉出现次数为0的),内层 0~9 组合数最多(10*9/2),总循环次数最大450,没有增大数据规模。

代码


/**
 * @date 2024-08-30 9:33
 */
public class SumDigitDifferences3153 {

    public long sumDigitDifferences(int[] nums) {
        int n = nums.length;
        int first = nums[0];
        int digitsLength = 0;
        while (first > 0) {
            digitsLength++;
            first /= 10;
        }
        int[][] cnt = new int[digitsLength][10];
        for (int i = 0; i < n; i++) {
            int d = 0;
            int num = nums[i];
            while (num > 0) {
                cnt[d++][num % 10]++;
                num /= 10;
            }
        }
        long res = 0L;
        for (int[] digit : cnt) {
            for (int i = 0; i < 10; i++) {
                if (digit[i] == 0) {
                    continue;
                }
                for (int j = i + 1; j < 10; j++) {
                    res += (long) digit[i] * digit[j];
                }
            }
        }
        return res;
    }

}

性能