文章

[LeetCode] 每日一题 2176. 统计数组中相等且可以被整除的数对(暴力法 & 哈希(反优化)))

题目描述

给你一个下标从 0 开始长度为 n 的整数数组 nums 和一个整数 k ,请你返回满足 0 <= i < j < n ,nums[i] == nums[j] 且 (i * j) 能被 k 整除的数对 (i, j) 的 数目 。

题目链接

https://leetcode.cn/problems/count-equal-and-divisible-pairs-in-an-array

示例输入

示例 1

输入:nums = [3,1,2,2,2,1,3], k = 2
输出:4
解释:
总共有 4 对数符合所有要求:
- nums[0] == nums[6] 且 0 * 6 == 0 ,能被 2 整除。
- nums[2] == nums[3] 且 2 * 3 == 6 ,能被 2 整除。
- nums[2] == nums[4] 且 2 * 4 == 8 ,能被 2 整除。
- nums[3] == nums[4] 且 3 * 4 == 12 ,能被 2 整除。

示例 2

输入:nums = [1,2,3,4], k = 1
输出:0
解释:由于数组中没有重复数值,所以没有数对 (i,j) 符合所有要求。

提示

  • 1 <= nums.length <= 100

  • 1 <= nums[i], k <= 100

解题思路

这题第一眼看上去就很直观,题目要求我们找出所有满足 nums[i] == nums[j] 且 i * j 能被 k 整除 的数对 (i, j),其中 0 <= i < j < n

一开始没有太多思路,索性就直接用暴力枚举:双重循环遍历所有可能的 (i, j) 组合,然后判断是否满足两个条件。如果都满足,就计数加一。虽然时间复杂度是 O(n^2),但在数据范围允许的前提下,这种方式最直接,也不容易出错。

后来我尝试用哈希表做了一些优化思考,比如将相同值的下标分组,然后对这些下标两两组合判断是否满足 i * j 能被 k 整除。不过实测下来,哈希版本虽然理论上减少了不必要的对比,但实际运行效率反而更低。这也让我意识到一个点:时间复杂度是相对的,实践中的性能还跟数据分布、常数开销有关,暴力有时候未必差 💡

代码实现

// 暴力解法
class Solution {
    public int countPairs(int[] nums, int k) {
        int n = nums.length;
        int ans = 0;
        for (int i = 0; i < n - 1; i++) {
            for (int j = i + 1; j < n; j++) {
                if (nums[i] == nums[j] && i * j % k == 0) {
                    ans++;
                }
            }
        }
        return ans;
    }
}
// 哈希优化尝试(实际更慢)
class Solution {
    public int countPairs(int[] nums, int k) {
        HashMap<Integer, List<Integer>> map = new HashMap<>();
        int ans = 0;
        for (int i = 0; i < nums.length; i++) {
            List<Integer> list = map.getOrDefault(nums[i], new ArrayList<>());
            for (Integer index : list) {
                if (index * i % k == 0) {
                    ans++;
                }
            }
            list.add(i);
            map.put(nums[i], list);
        }
        return ans;
    }
}

复杂度分析

  • 时间复杂度

    • 暴力解法:O(n²),每个下标对都判断一次

    • 哈希优化:理论上更优,但因为多了维护结构和乘法判断,实际效率反而下降

  • 空间复杂度

    • 暴力解法:O(1)

    • 哈希优化:O(n),用于记录相同值的下标

实测体验告诉我们:别急着优化,有时暴力也有春天 🚀

总结

本题给了一个很典型的例子:条件判断 + 双重限制 + 下标逻辑。很多时候题目条件看起来复杂,但直接暴力尝试反而是最快拿分的方法。后续优化也要结合实际测试结果来看效果,而不是只看理论时间复杂度。这种经验在面试和真实开发中都非常重要 🧠

希望这篇分享能为你带来启发!如果你有任何问题或建议,欢迎在评论区留言,与我共同交流探讨。

License:  CC BY 4.0