查找-滑动数组&二分数组

滑动数组算法应用
题目描述

给出一个整形数组nums和一个整数k,是否存在索引i和j,使得nums[i]==nums[j],且i和J之间的差不超过k。

示例1:
输入: nums = [1,2,3,1], k = 3
输出: true
示例 2:
输入: nums = [1,2,3,1,2,3], k = 2
输出: false

分析:这个数组中,中,如果有两个元素索引i和j,它们对应的元素是相等的,且索引j-i是小于等于k,那么就返回True,否则返回False。因为对于这道题目可以用暴力解法双层循环,即:

for i in range(len(nums)):
	for j in range(i+1,len(nums)):
		if i == j:
		return True
return False

固定滑动数组的长度为K+1,当这个滑动数组内如果能找到两个元素的值相等,就可以保证两个元素的索引的差是小于等于k的。如果当前的滑动数组中没有元素相同,就右移滑动数组的右边界r,同时将左边界l右移。查看r++的元素是否在l右移过后的数组里,如果不在就将其添加数组,在的话返回true表示两
元素相等。
因为滑动数组中的元素是不同的,考虑用set作为数据结构:

class Solution:
	def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
		record = set()
		for i in range(len(nums)):
			if nums[i] in record:
				return True
			record.add(nums[i])
			if len(record) == k+1:
				record.remove(nums[i-k])
		return False

时间复杂度为O(n),空间复杂度为O(n)

LeetCode220
题目描述

给定一个整数数组,判断数组中是否有两个不同的索引 i 和 j,使得nums [i] 和nums [j]的差的绝对值最大为 t,并且 i 和 j 之间的差的绝对值最大为 ķ。

示例 1:
输入: nums = [1,2,3,1], k = 3, t = 0
输出: true
示例 2:
输入: nums = [1,0,1,1], k = 1, t = 2
输出: true
示例 3:
输入: nums = [1,5,9,1,5,9], k = 2, t = 3
输出: false
分析实现

相比较上一个问题,这个问题多了一个限定条件,条件不仅索引差限定k,数值差也限定为了t。
将索引的差值固定,于是问题和上道一样,同样转化为了固定长度K+1的滑动窗口内,是否存在两个值的差距不超过 t,考虑使用滑动窗口的思想来解决。
在遍历的过程中,目的是要在“已经出现、但还未滑出滑动窗口”的所有数中查找,是否有一个数与滑动数组中的数的差的绝对值最大为 t。对于差的绝对值最大为t,实际上等价于所要找的这个元素v的范围是在v-t到v+t之间,即查找“滑动数组”中的元素有没有范围内的数存在。
因为只需证明是否存在即可,这时判断的逻辑是:如果在滑动数组查找比v-t大的最小的元素,如果这个元素小于等于v+t,即可以证明存在[v-t,v+t]。
那么实现过程其实和上题是一致的,只是上题中的判断条件是在查找表中找到和nums[i]相同的元素,而这题中的判断条件是查找比v-t大的最小的元素,判断其小于等于v+t,下面是实现的框架:

class Solution:
	def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool:
		record = set()
		for i in range(len(nums)):
			if 查找的比v-t大的最小的元素 <= v+t:
				return True
			record.add(nums[i])
				if len(record) == k+1:
					record.remove(nums[i-k])
			return False

对于如何寻找比v-t大的最小的元素,可以通过O(n)的解法来完成。

def lower_bound(self,array,v):
	array = list(array)
	for i in range(len(array)):
		if array[i] >= v:
			return i
		return -1

但是滑动数组作为set,是有序的数组。对于有序的数组,应该第一反应就是二分查找,于是考虑二分查找实现,查找比v-t大的最小的元素:

def lower_bound(self, nums, target):
	low, high = 0, len(nums)-1
	while low<high:
		mid = int((low+high)/2)
		if nums[mid] < target:
			low = mid+1
		else:
			high = mid
		return low if nums[low] >= target else -1

整体代码实现如下,时间复杂度为O(nlogn),空间复杂度为O(n):

class Solution:
	def containsNearbyAlmostDuplicate(self, nums, k, t) -> bool:
		record = set()
		for i in range(len(nums)):
			if len(record) != 0:
				rec = list(record)
				find_index = self.lower_bound(rec,nums[i]-t)
				if find_index != -1 and rec[find_index] <= nums[i] + t:
					return True
			record.add(nums[i])
			if len(record) == k + 1:
				record.remove(nums[i - k])
		return False
	def lower_bound(self, nums, target):
		low, high = 0, len(nums)-1
		while low<high:
			mid = int((low+high)/2)
			if nums[mid] < target:
				low = mid+1
			else:
				high = mid
		return low if nums[low] >= target else -1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值