1. 分治的思想:
分治算法通常遵循一种通用的模式:在解决规模较大的问题时,将其分解为若干规模较小的相似子问题,递归解决这些子问题,然后将各子问题的解合并为原问题的解,即分而治之。
2. 分治的基本步骤:
- 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题
- 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
- 合并:将各个子问题的解合并为原问题的解
3. 分治的经典例题理解:
二分搜索
二分搜索是一种在有序数组中查找特定元素的快速算法。其基本思想是比较数组中间元素与目标值:如果中间元素正好是目标值,则搜索结束;如果目标值小于中间元素,则在左侧子数组中继续搜索;如果目标值大,则在右侧子数组中搜索。
def binary_search(arr, low, high, x):
if high >= low:
mid = low + ((high - low) >> 1)
if arr[mid] == x:
return mid
elif arr[mid] > x:
return binary_search(arr, low, mid - 1, x)
else:
return binary_search(arr, mid + 1, high, x)
else:
return -1
arr = [2, 3, 4, 10, 40]
x = 10
result = binary_search(arr, 0, len(arr) - 1, x)
print("Element is present at index", result)
合并排序
归并排序是一种有效的排序算法,采用分治法的一个典型应用。它包括两个过程:分解 —— 将数组分成两半,对每部分递归地应用归并排序;合并 —— 将两个有序的数组合并成一个。
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) >> 1 # 使用位运算找到中点
L = arr[:mid]
R = arr[mid:]
merge_sort(L)
merge_sort(R)
i = j = k = 0
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
arr = [12, 11, 13, 5, 6, 7]
merge_sort(arr)
print("Sorted array is:", arr)
4. 复杂度分析:
二分搜索的时间复杂度分析
二分搜索的过程中,每次递归调用都会将搜索区间减半。如果我们将数组的长度表示为 N,那么:
- 在第一次迭代后,数组的长度减半,变为 N/2。
- 在第二次迭代后,长度变为 N/4,以此类推。
因此,二分搜索的时间复杂度可以通过求解如下递归关系得出:
T(N)=T(2N)+O(1)
这里的 O(1) 表示比较操作的时间复杂度。
通过迭代展开,我们可以发现深度为 O(logN),因此,二分搜索的总体时间复杂度为 O(logN)。
归并排序的时间复杂度分析
归并排序的过程包括将数组分解和合并数组两个主要部分。每一层递归调用都会涉及以下两个主要步骤:
- 分解步骤:将当前数组分成两半,这一步骤的时间复杂度为 O(1)。
- 合并步骤:将两个有序的子数组合并成一个有序数组,这一步骤的时间复杂度为 O(N),其中 N 是子数组的总长度。
归并排序的递归关系可以表示为:
T(N)=2T(2N)+O(N)
我们可以使用主定理来解这个递归关系。根据主定理(Master Theorem),该递归式符合第二种情况(即 a=b^d 的情况),我们得出归并排序的时间复杂度为 O(NlogN)。