LeetCode532. 数组中的 k-diff 数对


LeetCode532. 数组中的 k-diff 数对

题目描述

本题目来自LeetCode上的『532. 数组中的 k-diff 数对』

给定一个整数数组和一个整数 k,你需要在数组里找到 不同的 k-diff 数对,并返回不同的 k-diff 数对 的数目。

这里将 k-diff 数对定义为一个整数对 (nums[i], nums[j]),并满足下述全部条件:

  • 0 <= i < j < nums.length
  • |nums[i] - nums[j]| == k

注意|val| 表示 val 的绝对值。

示例1:

输入:nums = [3, 1, 4, 1, 5], k = 2
输出:2
解释:数组中有两个 2-diff 数对, (1, 3) 和 (3, 5)。
尽管数组中有两个1,但我们只应返回不同的数对的数量。

提示
  • 1 <= nums.length <= 10^4
  • -10^7 <= nums[i] <= 10^7
  • 0 <= k <= 10^7

题解1 - 哈希表

本题有一点 两数之和 进阶题的感觉。对于每一组数对 $(i,j)$,我们只需要找出较小值的数量即可,使用哈希表 mp 保存已经遍历过的数,再使用一个哈希集合 ans 实现去重功能,对于当前的数 $num$:

  • 查找 $num - k$ 是否已经遍历过,如果能找到,则将 $num-k$ 加入到 ans 中。
  • 查找 $num + k$ 是否已经遍历过,如果能找到,则将 $num$ 加入到 ans 中。

最后返回 ans 的大小即可。

代码

class Solution {
public:
    int findPairs(vector<int>& nums, int k) {
        unordered_set<int> mp;
        unordered_set<int> ans;
        for (const auto& num: nums) {
            if (mp.find(num - k) != mp.end()) {
                ans.emplace(num - k);
            }
            if (mp.find(num + k) != mp.end()) {
                ans.emplace(num);
            }
            mp.emplace(num);
        }
        return ans.size();
    }
};

复杂度分析

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(n)$

题解2 - 排序+二分查找

对于某个数对 $(i,j)$,可以枚举其中较小的数,然后查找另一个数即可。为了方便查找,需要先对数组进行排序,然后进行二分查找,设当前数为 $nums[i]$, 则查找目标为 $nums[i]+k$,查找范围为 $[i+1,n)$。

为了保证不重复计数,要跳过相同的数,利用数组的有序性,使用 i && nums[i - 1] == nums[i] 就可以判断。

代码

class Solution {
public:
    int findPairs(vector<int>& nums, int k) {
        int ans = 0, n = nums.size();
        sort(nums.begin(), nums.end());

        auto binarySearch = [&](int i, int x) -> int {
            int left = i + 1, right = n - 1;
            while (left <= right) {
                int mid = left + ((right - left) >> 1);
                if (nums[mid] < x) {
                    left = mid + 1;
                } else if (nums[mid] > x) {
                    right = mid - 1;
                } else {
                    return mid;
                }
            }
            return -1;
        };

        for (int i = 0; i < n; ++i) {
            if (i && nums[i] == nums[i - 1]) {
                continue;
            }
            if (binarySearch(i, nums[i] + k) != -1) {
                ++ans;
            }
        }

        return ans;
    }
};

复杂度分析

  • 时间复杂度:$O(n\log{n})$
  • 空间复杂度:$O(\log{n})$

题解3 - 排序+二分查找

基于题解2的分析,除了使用二分法之外,还可以用双指针。先将数组排序。左指针 $i$ 枚举数对中的较小值,右指针 $j$ 顺序查找数对中的较大值。

为了保证不重复计数,要跳过相同的数,利用数组的有序性,使用 i && nums[i - 1] == nums[i] 就可以判断。

代码

class Solution {
public:
    int findPairs(vector<int>& nums, int k) {
        int ans = 0, n = nums.size();
        if (n == 1) return 0;

        sort(nums.begin(), nums.end());

        for (int i = 0, j = 1; i < n - 1 && j < n; ++i) {
            if (i && nums[i - 1] == nums[i]) continue;
            if (j <= i) j = i + 1;
            while (j < n && nums[j] < nums[i] + k) ++j;
            if (j < n && nums[j] == nums[i] + k) ++ans;
        }

        return ans;
    }
};

复杂度分析

  • 时间复杂度:$O(n\log{n})$,其中双指针的复杂度为 $O(n)$。
  • 空间复杂度:$O(\log{n})$

文章作者: xitie2000
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 xitie2000 !
评论
  目录