分治法
分治一般可以直接使用递归实现,在不考虑空间消费的情况下和迭代方式时间消耗相差不多
==================================================================
分治一般形式: T(n) = k*T(n/m) + f(n)
k为子问题个数,一般均分或者等比分
n/m问题规模,一般情况下m已经确认了子问题的个数,可以通过变换减少为a个
f(n) 为数据的处理,划分和综合工作量,可以增加预处理,从而减少在递归里面的操作
也就是把递归里面的操作尽量放在循环体外面处理
==================================================================
问题规模和个数k*T(n/m),k<=m,当然理论上也有T(n-m)的情况,在这种情况下子问题变得很多,且子问题可能相互依赖,不独立,无法逐个解决,需要按照顺序解决子问题,通常那种情况下使用动态规划解决。
所以可以看出来分治和动态规划的区别:一个子问题多,多的还有存在依赖,一个子问题少,且子问题独立,从一般的状态转移方程也可以看出区别,一个是减法衰减,一个是除法衰减。
这里还有一个思考,假如一个问题可以分解成很多个子问题,且子问题独立,这时直接使用分治或者是直接使用动态规划,都是和蛮力算法没有区别,这时就需要考虑使用分治优化策略,减少子问题k,或者通过减少步骤f(n)来优化。
二分检索
二分检索原问题可以看成3个情况,检索目标就在middle,检索目标在middle左边,检索目标在middle右边,f[left,right] = f[middle] or f[left,middle-1] or f[middle+1,right],
实际上二分检索可以看成分支限界法,arr[middle] 和 target比较剪枝,是分支限界的话,那么就需要知道解空间,解空间就是,检索目标的位置,通过深度增加,不断精确检测目标的位置,直到位置精确到1,[模糊位置,缩小范围,缩小范围,…,精确到1],这个过程是满足多米诺性质的,可以用剪枝来减少搜索空间。
#%%
# 注意递归的返回值,递归的要返回的话,要前后一致,或者直接基于某一层考虑,把递归看成结果
def binary_Serach_recursive(arr,left,right,target):
middle = (left + right) // 2
# 递归出口
if left > right :
return(-1)
if arr[middle] == target:
return(middle)
elif arr[middle] < target:
# 这里没有return的话,结果就没法return出来
return binary_Serach_recursive(arr,middle+1,right,target)
else:
return binary_Serach_recursive(arr,left,middle-1,target)
def binary_Serach_iterative(arr,target):
left = 0
right = len(arr)-1
# 循环体条件
while left <= right:
middle = (left + right) // 2
if arr[middle] == target:
return middle
elif arr[middle] < target:
left = middle +1
else:
right = middle -1
return -1
#%%
arr = [7,3,66,33,22,66,99,0,1]
sort_arr = sorted(arr)
print(sort_arr)
print(binary_Serach_recursive(sort_arr,0,len(arr)-1,22))
print(binary_Serach_recursive(sort_arr,0,len(arr)-1,100))
print(binary_Serach_iterative(sort_arr,22))
print(binary_Serach_iterative(sort_arr,100))
[0, 1, 3, 7, 22, 33, 66, 66, 99]
4
-1
4
-1