递归算法与分治算法
递归算法
递归算法的定义
递归算法是一种编程技术,其基本思想是将一个复杂的问题分解为更小的子问题,然后逐个解决这些子问题。在递归中,函数会直接或间接地调用自身,这就是为什么它被称为"递归"。每个递归函数通常都有两个基本部分:基线条件(base case)和递归条件(recursive case)。
基线条件(base case)是递归结束的条件,也就是说,当满足这个条件时,函数将停止调用自身。递归条件(recursive case)是在满足这个条件的情况下,函数会继续调用自身,通常是在处理一个更小的子问题。
递归算法的中心思想
递归算法的实质是把问题分解成规模缩小的同类问题的子问题。递归式方法可以被用于解决很多的计算机科学问题,因此它是计算机科学中十分重要的一个概念。递归算法具有以下显著特点:首先,它有一个基本部分,即那些可以直接满足条件并输出的情况;其次,它有一个递归部分,即通过改变问题的规模(例如参数n),逐步使问题满足基本部分的条件,从而得出输出。在实现的过程中,递归算法通常采用分治法的思想,即将整体问题分解为多个子问题,分别求解后再将结果合并。
递归与迭代的比较
递归算法和迭代算法都是用来解决复杂问题的有效手段,它们将复杂问题分解为更小的子问题,然后逐步求解。然而,在实际操作中,二者具有显著的差异。
递归算法是通过函数自我调用来解决问题,其基本思想是将一个复杂的问题分解为更小的同类子问题,然后对子问题进行同样的处理,直到子问题无需进一步分解就可以解决。递归函数通常包含两个部分:基线条件(base case)和递归条件(recursive case)。基线条件是函数停止自我调用的条件,而递归条件则是继续调用自身的条件。
相反,迭代算法则是通过重复执行某一段代码或某个过程,每次处理的结果都作为下一次处理的输入,从而逐步逼近问题的解。迭代过程中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。
递归算法和迭代算法各有优缺点。递归算法具有代码简洁、易读、易理解的优点,但可能会消耗更多的系统资源,并可能导致栈溢出错误。相比之下,迭代算法通常具有更高的效率和更低的内存消耗,但可能缺乏递归的直观和简洁。因此,选择使用哪种算法应根据具体的问题和环境来决定。
递归算法的注意事项
使用递归需要注意避免出现死循环。为了确保递归正确工作,递归程序应该包含两个重要属性:基本情况和递推关系。基本情况用于保证程序调用能够及时返回,不在继续递归,从而保证了程序的可终止性;递推关系则可以将所有其他情况拆分到基本情况中去。
分治算法
分治算法的定义与中心思想
分治算法,字面上解释为“分而治之”,是一种在计算机科学中非常重要的算法设计策略。其核心思想是将一个规模较大的问题分解为两个或更多的相同或相似的子问题,然后将这些子问题进一步分解为规模更小的子问题,直到最后这些子问题可以简单地直接求解。原问题的解即子问题的解的合并。
具体来说,分治算法的基本步骤包括:首先,将一个复杂的问题分成两个或更多的相同或相似的子问题;其次,将这些子问题再分成规模更小的子问题;然后,对这些子问题进行求解;最后,将子问题的解合并得到原问题的解。
分治法适用于以下问题:原问题规模大且不易解决,但可以缩小到一定程度就可以容易解决;原问题可以分解为多个规模较小、求解方式相似的子问题,且各个子问题之间相互独立、互不影响。
分治算法与迭代算法的关系
分治算法和递归算法既有区别又有联系。首先,他们解决问题的方式不同。分治法是一种算法设计思想,它将问题分解成更小的子问题,然后将子问题的解合并起来得到原问题的解;它是一种解决复杂问题的策略,适用于处理一些可以分解为多个独立子问题的问题。而递归则是一种算法实现方法,它是通过函数调用自身来解决问题,即在函数内部直接或间接地自己调用自己。
其次,分治法可以使用递归来实现,但并非必须。换句话说,递归只是一种编程技巧,一种解决问题的思维方式,可以在很多算法中看到它的身影,如深度优先搜索、回溯等。然而,分治法还可以不用递归来实现,比如使用队列加循环也可以完成任务。
练习题
递归算法练习题
斐波那契数列
(1)题目描述
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
给定 n ,请计算 F(n) 。
(2)输入输出示例
示例 1:
输入:n = 2输出:1解释:F(2) = F(1) + F(0) = 1 + 0 = 1
示例 2:
输入:n = 3输出:2解释:F(3) = F(2) + F(1) = 1 + 1 = 2
(3)代码思路
A.定义一个函数,名为fib,接收一个参数n。
B.如果n为0或1,直接返回n。
C.否则,返回self.fib(n-1) + self.fib(n-2)的结果
(4)代码实现
class Solution(object):
def fib(self, n):
if n == 0 or n == 1:
return n
else:
return self.fib(n-1) + self.fib(n-2)
爬楼梯
(1)问题描述
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
(2)输入输出示例
示例 1:
输入:n = 2输出:2解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
示例 2:
输入:n = 3输出:3解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
(3)代码思路
A.定义一个递归函数,输入参数为楼梯的阶数 n。
B.如果 n 为 0 或 1,说明已经到达楼顶,返回 1。
C.如果 n 大于 1,那么可以从当前台阶爬 1 阶或者 2 阶到达楼顶。因此,我们需要计算爬到 n-1 阶和 n-2 阶的方法数之和。
D.最后返回爬到 n 阶的方法数。
(4)代码实现
class Solution(object):
def climbStairs(self, n):
if n == 0 or n == 1:
return 1
else:
return self.climbStairs(n-1) + self.climbStairs(n-2)
分治算法练习题
Pow(x,n)
(1)问题描述
实现 pow(x, n) ,即计算 x 的整数 n 次幂函数。
(2)输入输出示例
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
(3)代码思路
A.当n为0时,返回1,因为任何数的0次幂都等于1。
B.当n为负数时,将x取倒数,n取绝对值。
C.使用分治算法计算x的n次幂。具体来说,可以将n分为两部分,分别计算x的n/2次幂和x的n-n/2次幂,然后将这两个结果相乘得到最终结果。
D.如果n是偶数,那么x的n次幂可以表示为(x^(n/2))^2;如果n是奇数,那么x的n次幂可以表示为x * (x^((n-1)/2))^2。
(4)代码实现
class Solution(object):
def myPow(self, x, n):
if n == 0:
return 1
if n < 0:
x = 1 / x
n = -n
return self.fast_pow(x, n)
def fast_pow(self, x, n):
if n == 1:
return x
self.half_pow = self.fast_pow(x, n // 2)
if n % 2 == 0:
return self.half_pow * self.half_pow
else:
return x * self.half_pow * self.half_pow