所有数对中数位差之和

2024-08-30

题目:

你有一个数组 nums ,它只包含 整数,所有正整数的数位长度都 相同 。两个整数的 数位差 指的是两个整数 相同 位置上不同数字的数目。请你返回 nums所有 整数对里,数位差之和。

示例 1:

输入:nums = [13,23,12]

输出:4

解释: 计算过程如下: - 13 和 23 的数位差为 1 。 - 13 和 12 的数位差为 1 。 - 2312 的数位差为 2 。 所以所有整数数对的数位差之和为 1 + 1 + 2 = 4

示例 2:

输入:nums = [10,10,10,10]

输出:0

解释: 数组中所有整数都相同,所以所有整数数对的数位不同之和为 0 。

提示:

  • 2 <= nums.length <= 105
  • 1 <= nums[i] < 109
  • nums 中的整数都有相同的数位长度。

思路:

如果我们暴力枚举每一个数对的话,那么这一步需要O(n^2)
对于每一个数对,枚举不同位数需要O(len) len 是数字的位数

这样时间复杂度就比较高了

横看成岭侧成峰,换一个角度,把每一位拆开:
	计算个位数中的不同数对个数;
	计算十位数中的不同数对个数;
	计算百位数中的不同数对个数;
	……
单独考虑每个数位,此时问题变成:

给你一个长为 n 的数组 a,只包含数字 0 到 9,其中有多少个不同的数对?
做法有多种,一次遍历的做法如下。
	遍历 a,同时用一个长为 10 的数组 cnt 统计 0 到 9 每个数字的出现次数。假设现在遍历到 d = a[k],那么前面有 k 个数字,其中有 cnt[d] 个数和 d 是一样的,所以有 k − cnt[d] 个数和 d 是不一样的,这正是我们要统计的,加入答案。

代码实现时,可以外层循环枚举个位数、十位数、百位数等,内层循环枚举 nums;也可以外层循环枚举 nums,内层循环枚举个位数、十位数、百位数等。下面代码用的后者。

代码:

class Solution {
public:
    long long sumDigitDifferences(vector<int>& nums) {
        long long ans = 0;
        long long size = 0, testNum = nums[0], n = nums.size();
        while (testNum) {
            size++;
            testNum /= 10;
        }
        while (size) {
            size--;
            unordered_map<int, long long> hash;
            for (int i = 0; i < nums.size(); i++) {
                hash[nums[i] % 10]++;
                nums[i] /= 10;
            }
            for (auto kv : hash) {
                ans += kv.second * (n - kv.second);
            }
        }
        return ans / 2;  // 由于每个数字都计算了两次,所以除2
    }
};