1.二分查找
二分查找:根据中间元素与目标值的大小关系将数组不断进行切分成两半,因为一个长为n的数组最多可以二分logn次,所以二分查找的时间复杂度为o(logn)。
1.1例题-搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。你可以假设数组中无重复元素。
思路:
- 计算中间元素的值
- 比较中间元素和目标值的大小关系,若前者大,则搜索区间缩小到左半区间,若前者小,则缩小到右半区间。
- 重复1,2过程直到中间元素和目标值相等或者搜索区间只剩下一个元素,此时头指针等于尾指针。
- 讨论目标值不存在于数组中的情况,若最终指针指向的元素小于目标值,则返回指针索引+1;若最终指针指向的元素大于目标值,则返回指针索引。
代码如下:
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0 # 头指针
right = len(nums) - 1 # 尾指针
result = -1
while left < right:
# mid 指向中间位置的指针
mid = left + (right - left) // 2 # 避免left+right溢出
if nums[mid] > target:
right = mid - 1
elif nums[mid] < target:
left = mid + 1
else:
result = mid
break
if result == -1:
if nums[left] >= target:
result = left
else:
result = left + 1
return result
结果如下:
2.考虑的基本数据结构
2.1第一类:查找有无–set
元素’a’是否存在,通常用set:集合,set只存储键,而不需要对应其相应的值。set中的键不允许重复
编写一个算法来判断一个数 n 是不是快乐数。
2.2例题- 快乐数
「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环
但始终变不到 1。如果 可以变为 1,那么这个数就是快乐数。如果 n 是快乐数就返回 True ;不是,则返回 False 。
思路:通过set集合记录n的变化值,判断原始n是否出现第二次,第二次代表进入了无限循环,返回False;若n的变化过程出现1,返回True,是一个快乐数。
代码如下:
class Solution:
def isHappy(self, n: int) -> bool:
# 有无限循环,想到哈希set可以判断是否存在
def get_next(n):# 求平方和获取下一个数
total_sum = 0
while n > 0:
n, digit = divmod(n, 10)#获得商和余数
total_sum += digit ** 2#平方和
return total_sum
seen = set()# 集合set
while n != 1 and n not in seen:#n==1或者n进行无限循环 退出while循环
seen.add(n)
n = get_next(n)
return n == 1# 判断已何种情况退出循环
结果如下:
2.3例题- 同构字符串
给定两个字符串 s 和 t,判断它们是否是同构的。
如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的。
所有出现的字符都必须用另一个字符替换,同时保留字符的顺序。两个字符不能映射到同一个字符上,但字符可以映射自己本身。
思路:限制条件是两个字符不能映射到同一个字符上,若某对字符已经存在一个映射关系,则发现映射到相同字符的新映射关系直接返回False。因为每次只关注一个方向,保证双向映射都符合条件,调换字符串位置再执行一次遍历。
代码如下:
class Solution:
def isIsomorphic(self, s: str, t: str) -> bool:
def helper(s, t):
seenDict = set() # 记录映射的set
seenKey = set() # 记录映射对象的set
for i in range(len(s)):
# 两个字符不能映射到同一个字符
if t[i] not in seenKey: # 未出现映射到该字母的映射
# 添加新映射
seenDict.add((s[i], t[i]))
seenKey.add(t[i])
# 以往存在这个映射,跳出操作
elif (s[i], t[i]) in seenDict:
continue
else: # 错误情况:两个字符映射到同一个字符
return False
return True # 安全遍历完,返回True
return helper(s, t) and helper(t, s) # 合并两次映射结果
结果如下:
类似的利用set进行查找的题还有349. 两个数组的交集
未完待续