1.1分治算法
1.1.1分治算法思想
将原问题分解成与“原问题相同但是规模更小”的子问题,并可以反复执行这个过程,使得问题规模减小到可以求解为止。下面我们将举出是三个例子来介绍分治算法
1.1.2.快速排序
问题描述:给定1000个数,从小到大进行排序。
问题分析: 先选择一个“标准”A,按照“比A小”和“比A大”将原来的数列分为两类,这样,只需要将两个子序列分别排好序,然后再合并到一块就ok了。
1.1.3.大数相乘算法
问题:两个很大的数相乘,如何更快的解决?
两个很大的数相乘,普通算法的时间复杂度为O(n^2)。该算法将原来的时间复杂度降低到O(3^1.585)
步骤:
首先,将n位大数x和y进行分解。
然后,x·y就变成了下面这样
并且满足
这样的话,乘法又能变成加法了!计算复杂度又大大的降低了!
分治思想小结
第一:数学归纳是使用分治思想
第二:分治思想不一定使用递归结构;递归结构是循环结构的一种,也是分治思想应用最多的一种程序结构,但是不一定要使用它!关键在于能够写出递归公式以及是否有必要使用递归算法。比如上边提到的快速傅里叶变换算法,就没有用到递归!
第三:分治思想的核心是“如何分”
采用分治法的时我们会将其划分成比较小的子问题,从子问题中找出局部最优,然后将子问题的局部最优进行合并,这时候就会出现出现重叠子问题和重叠子结构,就需要我们后续的动态规划问题处理....不急,下面将会介绍
2.1.递归算法
2.1.1运用递归需要注意
- 递归的退出条件
- 递归时应该传递的参数
- 递归一定是从后往前的
其实递归也是动态规划的一种思想:下面我们举个例子看看
代码实现
def fblq(n):
if n<=0:
return 0
elif n==1:
return 1
else:
return fblq(n-2)+fblq(n-1)
print(fblq(10))
3.1动态规划
有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶。要求用程序来求出一共有多少种走法。(比如,每次走1级台阶,一共走10步,这是其中一种走法。我们可以简写成 1,1,1,1,1,1,1,1,1,1。)
这个问题就用到了动态规划,动态规划是一种分阶段求解决策略的思想参考文档
解决方案:
- F(1) = 1;
- F(2) = 2;
- F(n) = F(n-1)+F(n-2)(n>=3)
动态规划:重叠子结构,边界,状态转移公式
代码实现:
def way(n):
if n<=0:
return 0
if n==1:
return 1
if n==2:
return 2
return way(n-1)+way(n-2)
print(way(10))
时间复杂度计算:
相同的颜色代表了方法被传入相同的参数。
时间复杂度为O(n**2)
相同元素的值被计算了两次,我们可以使用哈希表将计算的结果暂时存起来,这种方法叫备忘录算法
优化:代码实现
def way(n,ds):
if n<=0:
return 0
if n==1:
return 1
if n==2:
return 2
if n in ds:
return ds[n]
else:
value=way(n-1,ds)+way(n-2,ds)
ds[n]=value
return value
ds=dict()
for i in range(11):
print(way(i, ds))
时间复杂度为O(n),尽管提高了时间复杂度,但是空间复杂度似乎是降低了,我们能不能也也将空间复杂度提高?当然,我们是自顶向下,为什么不能自底向上尼?F(3)基于F(1)和F(2),而F(4)基于F(2)和F(3),我们可以先计算F(1)和F(2)再计算F(10),这样是不是就降低了存储空间吧
给出一道比较复杂的问题:
有一个国家发现了5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人数也不同。参与挖矿工人的总数是10人。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半金矿。要求用程序求解出,要想得到尽可能多的黄金,应该选择挖取哪几座金矿?