0220. Contains Duplicate I I I

220. Contains Duplicate III #

题目 #

Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

Example 1:

Input: nums = [1,2,3,1], k = 3, t = 0
Output: true

Example 2:

Input: nums = [1,0,1,1], k = 1, t = 2
Output: true

Example 3:

Input: nums = [1,5,9,1,5,9], k = 2, t = 3
Output: false

题目大意 #

给出一个数组 num,再给 K 和 t。问在 num 中能否找到一组 i 和 j,使得 num[i] 和 num[j] 的绝对差值最大为 t,并且 i 和 j 之前的绝对差值最大为 k。

解题思路 #

  • 给出一个数组,要求在数组里面找到 2 个索引,ij,使得 | nums[i] - nums[j] | ≤ t ,并且 | i - j | ≤ k
  • 这是一道滑动窗口的题目。第一想法就是用 ij 两个指针,针对每个 i ,都从 i + 1 往后扫完整个数组,判断每个 ij ,判断是否满足题意。j 在循环的过程中注意判断剪枝条件 | i - j | ≤ k。这个做法的时间复杂度是 O(n^2)。这个做法慢的原因在于滑动窗口的左边界和右边界在滑动过程中不是联动滑动的。
  • 于是考虑,如果数组是有序的呢?把数组按照元素值从小到大进行排序,如果元素值相等,就按照 index 从小到大进行排序。在这样有序的数组中找满足题意的 ij,滑动窗口左边界和右边界就是联动的了。窗口的右边界滑到与左边界元素值的差值 ≤ t 的地方,满足了这个条件再判断 | i - j | ≤ k,如果右边界与左边界元素值的差值 > t 了,说明该把左边界往右移动了(能这样移动的原因就是因为我们将数组元素大小排序了,右移是增大元素的方向)。移动左边界的时候需要注意左边界不能超过右边界。这样滑动窗口一次滑过整个排序后的数组,就可以判断是否存在满足题意的 ij 。这个做法的时间主要花在排序上了,时间复杂度是 O(n log n)。

代码 #


package leetcode

import "sort"

// 解法一 排序 + 滑动窗口
func containsNearbyAlmostDuplicate(nums []int, k int, t int) bool {
	if len(nums) < 2 {
		return false
	}
	elemList := make([]*elem, len(nums))
	for i, num := range nums {
		elemList[i] = &elem{num, i}
	}
	sort.SliceStable(elemList, func(i, j int) bool {
		if elemList[i].val != elemList[j].val {
			return elemList[i].val < elemList[j].val
		}
		return elemList[i].idx < elemList[j].idx
	})
	i, j := 0, 1
	for j < len(elemList) {
		if elemList[j].val-elemList[i].val <= t {
			if abs(elemList[j].idx-elemList[i].idx) <= k {
				return true
			}
			j++
		} else {
			i++
			if j <= i {
				j++
			}
		}
	}
	return false
}

type elem struct {
	val int
	idx int
}

// 解法二 滑动窗口 + 剪枝
func containsNearbyAlmostDuplicate1(nums []int, k int, t int) bool {
	if len(nums) <= 1 {
		return false
	}
	if k <= 0 {
		return false
	}
	n := len(nums)
	for i := 0; i < n; i++ {
		count := 0
		for j := i + 1; j < n && count < k; j++ {
			if abs(nums[i]-nums[j]) <= t {
				return true
			}
			count++
		}
	}
	return false
}


⬅️上一页

下一页➡️

Calendar Sep 6, 2020
Edit Edit this page
本站总访问量:  次 您是本站第  位访问者