220. 存在重复元素 III

在这里插入图片描述

对于本题,由于题中限定了abs(i - j) <= k的条件,应该首先想到滑动窗口,因为滑动窗口可以满足此限定。在窗口内对的数据进行相关操作来判断是否有符合题意的数据

首先窗口的大小应该为k,这样可以满足题中的 abs(i - j) <= k 条件。

其次,对于窗口内的数据,可以采用两个for循环来进行判断是否有满足题意的组合。由于题中要求的是相减的绝对值,这样对于for循环,就可以省去一半的循环了,因为 |a - b | = |b - a|

以下是Go语言代码:

func containsNearbyAlmostDuplicate(nums []int, k int, t int) bool {
	if k >= len(nums) {
		k = len(nums) - 1
	}
	for start := 0; start+k < len(nums); start++ {
		subArr := nums[start : start+k+1]
		for i := 0; i <= k; i++ {
			for j := i + 1; j <= k; j++ {
				if abs(subArr[i]-subArr[j]) <= t {
					return true
				}
			}
		}
	}
	return false
}

func abs(num int) int {
	if num < 0 {
		return -num
	}
	return num
}

但是,暴力解法在执行时因为时间复杂度过高,导致执行超时

在这里插入图片描述

因此,需要对此算法中耗时的地方进行优化。对于算法的优化,思路无非就是时空转换。我们想降低时间复杂度,可以通过增加空间复杂度的方式来进行。

回看上面的代码,最耗时的操作在于判断滑动窗口内是否存在abs[i] - abs[j] <= t,对于这个操作,上面的代码使用的是穷举法,时间复杂度为O(n²),若我们换成桶排序的思路,则可以将这部分操作时间复杂度降低为O(n)

我们可以维护多个长度为t+1的桶,若有两个元素同时落到一个桶内,则代表满足题中条件,若落到两个相邻的桶,则需要单独判断这两个值相减的绝对值是否满足题意。

如下图所描述:

在这里插入图片描述

因为 t = 3 则将数字 0 - 3分到一个桶,4 -7 分到一个桶 ,8 - 11 分到一个桶

对于最开始的滑动窗口,因为长度为3,所以截取前三个元素,这三个元素分别对应了三个桶

在放入第一个元素时,被分配到了第一个桶,且相邻桶内无元素。

在放入第二个元素时,其相邻的第一个桶内有元素,但 5 - 1 > 3 所以不满足

在放入第三个元素时,其相邻的第二个桶内有元素,但 9 - 5 > 3 所以不满足

以此类推滑动窗口,到结束均不满足,所以返回false

对应的Go代码如下:

func containsNearbyAlmostDuplicate(nums []int, k, t int) bool {
	mp := map[int]int{}
	for i, x := range nums {
		id := getID(x, t+1)
		if _, has := mp[id]; has {
			return true
		}
		if y, has := mp[id-1]; has && abs(x-y) <= t {
			return true
		}
		if y, has := mp[id+1]; has && abs(x-y) <= t {
			return true
		}
		mp[id] = x
		if i >= k {
			delete(mp, getID(nums[i-k], t+1))
		}
	}
	return false
}

func getID(x, w int) int {
	if x >= 0 {
		return x / w
	}
	return (x+1)/w - 1
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

对于上述代码,可能看过的人会有两处疑问:

1.对于每个桶内,并没有用数组保存,而是只保存了一个值,不怕被覆盖进而导致其他桶与这个桶相邻却得不到正确结果吗?

这里如果出现了覆盖的情况,会直接返回true的,所以不存在上述情况。

2.getID对于x<0部分的没有看明白是为什么。

对于大于0的部分,若t = 3 则 0-3,4-7,8-11...是一组
但对于小于0的部分,原则上应该是 -4 - -1,-8 - -5 ...是一组,但是如果按照x>=0的方法进行计算,则 -4 与 -1分到了两个组。所以需要先+1,将其变成 -3 - 0与正数保持一致进行分组,在分好组后-1,与0-9中的0进行区别。得出的正好是 -4 - -1这一组
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值