532. 数组中的 k-diff 数对

58 阅读1分钟

题目:
给你一个整数数组 nums 和一个整数 k,请你在数组中找出 不同的 k-diff 数对,并返回不同的 k-diff 数对 的数目。

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

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

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

算法:

方法一:hash 表
这种朴素方法都想不出来了吗

image.png 时间复杂度,空间复杂度O(n)

func findPairs(nums []int, k int) int {
    count := 0
    numCount := make(map[int]int)
    for i := range nums {
        numCount[nums[i]] ++
    }
    for num,c := range numCount {
        if k == 0 {
            if c > 1 {
                count ++
            }
        } else {
            if numCount[num - k] > 0 {
                count ++ 
            }
            if numCount[num + k] > 0 {
                count ++ 
            }
        }
        numCount[num] = 0
    }
    return count
}

方法二:hash table + 二分
目的是用数组替代map,减少内存的使用 。 数组代替map,一个去重保存元素(list),一个保存元素和在nums中的出现次数。 可以看到内存使用确实好不少。 image.png 时间复杂度:O(n) + O(n) + ? 时间复杂度O(n)

func findPairs(nums []int, k int) int {
    count := 0
    // list数组有序保存去重之后的nums
    sort.Ints(nums)
    list := make([]int, 0)
    for i := range nums {
        if len(list) == 0 || list[len(list) - 1] != nums[i] {
            list = append(list, nums[i])
        }
    }
    // cnt 维护list.index和出现次数的关系
    cnt := make([]int, len(list))
    for i := range nums {
        index := find(list, nums[i])
        if index >= 0 {
            cnt[index] ++
        }
        
    }
    // 遍历nums,看num + k和num - k在cnt中是否存在,更新count,完了设置cnt[i]=0
    index := 0
    for i := range list {
        if k == 0 {
            if cnt[index] > 1 {
                count ++
            }
        } else {
            a, b := find(list,  list[i] + k), find(list, list[i] - k)
            if a != -1 && cnt[a] > 0 {
                count ++
            }
            if b != -1 && cnt[b] > 0 {
                count ++
            }
        }
        
        cnt[index] = 0
        index ++
    }
    return count
}

// 找到num在list中的下标,如果不存在返回-1
func find(list []int, num int) int {
    left, right := 0, len(list)  -1
    for left <= right {
        mid := (left + right) >> 1
        if list[mid] == num {
            return mid
        } else if list[mid] < num {
            left = mid + 1
        } else {
            right = mid - 1
        }
    }
    return -1
}