查找
1.查找表
1.1 什么是查找表
查找表是由同一类型的数据元素构成的集合。
考虑的基本数据结构,可将查找表分为:
- 第一类: 查找有无–set
元素’a’是否存在,通常用set:集合。set只存储键,而不需要对应其相应的值。set中的键不允许重复
- 第二类: 查找对应关系(键值对应)–dict
元素’a’出现了几次:dict–>字典。dict中的键不允许重复
- 第三类: 改变映射关系–map
通过将原有序列的关系映射统一表示为其他,在查找表中只做查找操作,而不改动表中数据元素,称此类查找表为静态查找表;反之,在查找表中做查找操作的同时进行插入数据或者删除数据的操作,称此类表为动态查找表。
1.2 查找表的算法运用
1.2.1 349 Intersection Of Two Arrays 1
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1 = set(nums1)
return set([i for i in nums2 if i in nums1])
使用集合求交集:
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
return set(num1)&set(num2)
2.碰撞指针
2.1 算法定义
对撞指针的定义是对一个排好序的数组,存在两个指针,分别指向最左端和最右端;我们可以通过与目标值的对比,动态的移动做指针和右指针的方式,接近目标值。
注意,碰撞指针需要数组为已经排好序。
碰撞指针法的时间复杂度,对于无序列表,复杂度大于nlogn 小于n^2,优于暴力解法。也有的地方,将其复杂度认为为n(O(n)+O(nlogn)=O(n)),个人觉得应该大于nlogn。
2.2 算法应用
167 两数之和 II - 输入有序数组
已排好序的数组,十分适合碰撞指针法
class Solution:
def twoSum(self, numbers: List[int], target: int) -> List[int]:
low, high = 0, len(numbers) - 1
while low < high:
total = numbers[low] + numbers[high]
if total == target:
return [low + 1, high + 1]
elif total < target:
low += 1
else:
high -= 1
return [-1, -1]
3.滑动数组
3.1 算法介绍
我们学习过计算机网络都知道为了避免拥塞发生,在网络传输时有滑动窗口协议控制传输时流量。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。这个跟我们今天说的滑动窗口算法是一个原理。
滑动窗口是数组/字符串问题中常用的抽象概念。窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即[left,right)(左闭,右开)。而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。
3.2 算法应用
220 Contains Dupliccate Ⅲ
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
4 小结
查找算法,一方面可利用特定数据结构,实现快速索引,利用空间换取时间,另一方面,可使用类似于回溯法,在一个区间内不断查找符合要求的子结构,并在子结构不满足要求时,调整边界,进行下一次查找。
其中碰撞指针法,二分查找适合已排序数组。