算法常用思想
递归
1.什么是递归
函数在自身内部调用自己的一种编程技巧叫递归。递归三大要素:
- 明确函数功能
- 找出递归结束条件
- 找出函数等价关系式(递推公式)
递归总的来说:先递进,后回归。
2.应用条件
- 基线条件:函数调用本身,子问题和原始问题求解方法相同,且子问题规模更小。
- 递归条件:递归不能是无限的。递归条件避免无限循环。
- 斐波那契数列
- 阶乘
- 二叉树遍历
3.举例
斐波那契数列
def f(x):
if x <= 2: # 基线条件:结束递归
return 1
else: # 递归条件
return f(x-1) + f(x-2) # 函数等价关系式
x = int(input("input a intger"))
n = f(x)
print(n)
小青蛙跳台阶
class Solution(object):
def numWays(self, n):
a,b = 1,1
for _ in range(n):
a,b = b, a+b
return a % 1000000007
汉诺塔问题
class Solution:
def hanota(self, A: List[int], B: List[int], C: List[int]) -> None:
n = len(A)
self.move(n, A, B, C)
# 定义move 函数移动汉诺塔
def move(self,n, A, B, C):
if n == 1:
C.append(A[-1])
A.pop()
return
else:
self.move(n-1, A, C, B) # 将A上面n-1个通过C移到B
C.append(A[-1]) # 将A最后一个移到C
A.pop() # 这时,A空了
self.move(n-1,B, A, C) # 将B上面n-1个通过空的A移到C
作者:z1m
链接:https://leetcode-cn.com/problems/hanota-lcci/solution/tu-jie-yi-nuo-ta-de-gu-shi-ju-shuo-dang-64ge-pan-z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
5.递归的优缺点
优点:代码简洁,易于理解
缺点:时间空间消耗大,重复计算多,调用栈溢出。
改进:一些数据在递归过程中会重复计算,建立缓存存储这些计算过的数据,减少计算量,这种算法也叫备忘录算法。
链接: https://www.cxyxiaowu.com/7259.html
分治
1 什么是分治
分治:分而治之,即把一个复杂的问题分解成多个相同或相似的子问题,将子问题不断分解直至问题简单到可以直接解出。再将子问题的解合并就可以的到原问题的解。
2 分治步骤
分解——>求解——>合并
3.分治应用
二分查找
归并排序
快速排序
汉诺塔问题
贪心(NP)
1 什么是贪心
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
2 算法流程
1.建立数学模型描述问题
2.将原问题分成若干个子问题
3.找出子问题的最优解
4.把子问题的局部最优解合并成一个解
3.应用
prim最小生成树算法
换酒瓶问题#1518
class Solution(object):
def numWaterBottles(self, numBottles, numExchange):
"""
:type numBottles: int
:type numExchange: int
:rtype: int
"""
res = numBottles
drinked = numBottles
while res >= numExchange:
res = res - numExchange
drinked += 1
res += 1
return drinked
动态规划(DP)
1 什么动态规划
动态规划背后的基本思想:大致上,若要解一个给定问题,我们需要解其不同部分(即子问题),再根据子问题的解以得出原问题的解。动态规划往往用于优化递归问题,例如斐波那契数列,如果运用递归的方式来求解会重复计算很多相同的子问题,利用动态规划的思想可以减少计算量。
一句话解释就是:记住你之前得到的答案。
动态规划三要素:重叠子问题,最优子结构,转移方程。
动态规划的一般问题是最值问题,核心为“穷举”。
动态规划脱离了递归,通常由循环迭代完成计算。
2 算法流程
问题拆解,找到问题之间的联系
状态定义
找出递推方程
实现
回溯
1.什么是回溯:
回溯算法类似枚举的尝试搜索过程。基本思想是:从一条路往前走,能进则进,不进则退回上个路口,换一条路继续走。
回溯问题也是决策树遍历问题。需要思考三个问题:
路径、选择列表、结束条件。
2.回溯算法框架:
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
3.全排列问题:
def permutation(nums, p, q):
if p == q:
s.append(list(nums))
else:
for i in range(p, q):
nums[i], nums[p] = nums[p], nums[i]
permutation(nums, p + 1, q)
nums[i], nums[p] = nums[p], nums[i]
s = []
nums = [i for i in range(1, 4)]
permutation(nums, 0, len(nums))
print(s)