递归、分治、动态规划、贪心、回溯——区别和联系

本文详细介绍了递归、动态规划、贪心算法和回溯这四种重要的算法思想。递归是解决问题的基础,动态规划通过保存子问题的解以避免重复计算,贪心算法寻求局部最优解并尝试推导全局最优,而回溯算法在搜索过程中通过剪枝优化效率。动态规划与分治策略相似,但更专注于解决有重叠子问题的情况;贪心与动态规划都采用递推方式,但贪心不保证全局最优。回溯法与分治算法都使用递归,但回溯包含剪枝机制以避免无效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

递归是一种编程技巧,一种解决问题的思维方式;
其他的思想都是基于递归的!

分治算法动态规划很大程度上是递归思想基础上的(虽然动态规划的最终版本大都形式上不是递归了,但解题思想离不开递归)解决更具体问题的两类算法思想;
贪心算法动态规划算法的一个子集,可以更高效解决一部分更特殊的问题。


一、动态规划和递归(回溯,分治)

递归和动态规划是从保存过程信息角度划分的。

  • 递归:
    做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。

  • 动态规划:
    动态规划其实和分治策略是类似的,也是将一个原问题分解为若干个规模较小的子问题,递归的求解这些子问题,然后合并子问题的解得到原问题的解。

  • 区别:
    区别在于这些子问题会有重叠,一个子问题在求解后,可能会再次求解,于是我们想到将这些子问题的解存储起来,当下次再次求解这个子问题时,直接拿过来就是
    其实就是说,动态规划所解决的问题是分治策略所解决问题的一个子集,只是这个子集更适合用动态规划来解决从而得到更小的运行时间。即用动态规划能解决的问题分治策略肯定能解决,只是运行时间长了。

二、贪心算法和动态规划

贪心和动态规划是从全局最优角度划分的:
能从局部最优推导出全局最优就是贪心,否则就是动态规划。

  • 贪心算法:
    贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留。

  • 联系:
    动态规划和贪心算法都是一种递推算法。
    均由局部最优解来推导全局最优解。

  • 区别
    1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解
    2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解
    3.边界条件:即最简单的,可以直接得出的局部最优解

三、回溯算法和分治算法

回溯与其他递归算法是从剪枝角度划分的

  • 分治策略:
    将原问题分解为若干个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。
    因为在求解大问题时,需要递归的求小问题,因此一般用递归的方法实现,即自顶向下(下面解释)

  • 回溯算法
    回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
    回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。

  • 分治与回溯的区别:
    递归是一种算法结构。递归会出现在子程序中,形式上表现为直接或间接的自己调用自己。典型的例子是阶乘,计算规律为:n!=n×(n−1)!,如果用 C++ 代码表示,基本如下所示。回溯是一种算法思想,它是用递归实现的。回溯的过程类似于穷举法,但回溯有“剪枝”功能,即自我判断过程。例如有求和问题,给定有 7 个元素的组合 [1, 2, 3, 4, 5, 6, 7],求加和为 7 的子集。累加计算中,选择 1+2+3+4 时,判断得到结果为 10 大于 7,那么后面的 5, 6, 7 就没有必要计算了。这种方法属于搜索过程中的优化,即“剪枝”功能。


int fac(int n) {
    if(n == 1) return n;
    else 
        return (n*fac(n - 1)); 
}

### 关于分治动态规划贪心算法回溯的练习题与代码实现 #### 分治算法 分治算法通过将一个问题分解成若干个小规模相同类型的子问题来解决。对于排序问题中的快速排序,可以通过选取一个基准元素,把数组分成两部分,一部分都比这个基准值小,另一部分都大,递归地对这两部分进行同样的操作。 ```python def quicksort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quicksort(left) + middle + quicksort(right) ``` 此段代码展示了如何利用分治策略解决问题[^1]。 #### 动态规划 动态规划适用于有重叠子问题并具备最优子结构性质的问题。以经典的斐波那契数列为例子: ```python def fibonacci(n, memo={}): if n in memo: return memo[n] elif n <= 2: f = 1 else: f = fibonacci(n-1, memo) + fibonacci(n-2, memo) memo[n] = f return f ``` 上述函数采用记忆化技术优化了计算过程,有效减少了重复运算次数。 #### 贪心算法 当面对某些特定条件下的最优化问题时,可以直接做出局部最优的选择从而得到全局最优解。考虑活动安排问题,在给定一系列活动各自的起始时间结束时间的情况下,尽可能多地选出不冲突的活动参与。 ```python def activity_selection(activities): activities.sort(key=lambda x: x[1]) # 按照结束时间升序排列 selected_activities = [] last_end_time = float('-inf') for start, end in activities: if start >= last_end_time: selected_activities.append((start,end)) last_end_time = end return selected_activities ``` 这段程序实现了基于贪心原则挑选最多数量互斥事件的方[^2]。 #### 回溯 回溯是一种试探性的搜索方,它尝试构建解决方案直到发现当前路径不可行为止;此时会撤销最后一步决策继续探索其他可能性。八皇后问题是典型的运用场景之一。 ```python def solve_n_queens(n): solutions = [] def backtrack(row=0, columns=[], diag1=set(), diag2=set()): if row == n: solutions.append(columns[:]) return for col in range(n): if (col not in columns and row - col not in diag1 and row + col not in diag2): columns.append(col) diag1.add(row-col) diag2.add(row+col) backtrack(row+1, columns, diag1, diag2) columns.pop() diag1.remove(row-col) diag2.remove(row+col) backtrack() board_formats = [['.'*i+'Q'+'.'*(n-i-1) for i in sol] for sol in solutions] return board_formats ``` 该片段定义了一个求解N皇后的通用框架,并返回所有可能的结果列表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Strive_LiJiaLe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值