参考文章
一、D&C:分而治之,它是一种著名的递归式问题解决方法。
步骤:
(1)找出基线条件,这种条件必须尽可能简单。相当与递归的终止条件。
在处理列表时,基线条件很可能是空数组或只包含一个元素
(2)不断将问题分解(或者说缩小规模),直到符合基线条件
1. 自顶向下叫做递归,自底向上叫做递推
// 问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?
// 1. 递归
public int f(int n) {
if (n <= 2) {
return n;
} else {
return f(n - 1) + f(n - 2);
}
}
// 2. 备忘录法
//数组的大小根据具体情况来,由于int数组元素的的默认值是0
//因此我们不用初始化
int[] arr = new int[1000];
public int f(int n) {
if (n <= 2) {
return n;
} else {
if (arr[n] != 0) {
return arr[n];//已经计算过,直接返回
} else {
arr[n] = f(n-1) + f(n-2);
return arr[n];
}
}
}
// 3. 自底向上
public int f(int n) {
if(n <= 2)
return n;
int f1 = 1;
int f2 = 2;
int sum = 0;
for (int i = 3; i <= n; i++) {
sum = f1 + f2;
f1 = f2;
f2 = sum;
}
return sum;
}
2. 当你在使用递归解决问题的时候,要考虑以下两个问题
- 是否有状态重复计算的,可不可以使用备忘录法来优化。
- 是否可以采取递推的方法来自底向上做,减少一味递归的开销。
3. 遇到递归的题,一定要考虑是否可以剪枝,是否可以把递归转化成递推。
二、常见的分治题型
大多数应该运用于一维题目中,例如字符串、一维数组相关的题,可以考虑使用分治的方法
例题1:二路归并排序
# 二路归并排序 递归
# 两两合并,分治
def merge(arr, left, mid, right):
i = left
j = mid
res = []
while i < mid and j < right+1:
if arr[i] > arr[j]:
res.append(arr[j])
j = j + 1
else:
res.append(arr[i])
i = i + 1
while i < mid:
res.append(arr[i])
i = i + 1
while j < right + 1:
res.append(arr[j])
j = j + 1
p = len(res)
for k in range(p):
arr[left+k] = res[k]
def mergeSort(arr, left, right):
# 基准因子, 当只剩一个元素时, 直接返回
if left >= right:
return
mid = right + int((left - right)/2)
# 左边数组进行归并排序
mergeSort(arr, left, mid-1)
# 右边数组进行归并排序
mergeSort(arr, mid, right)
# 判断升序时返回
if arr[mid-1] <= arr[mid]:
return
merge(arr, left, mid, right)
写在最后
如果觉得本文对你有帮助的话,可以为我点个赞哈,你的关注和支持是我坚持下去最大的鼓励。
对文章有什么建议和意见,也欢迎留言告诉我,期待你的回馈。