递归与分治算法解析
递归
递归的概念:直接或者间接调用自身算法称为递归算法,像俄罗斯套娃一样一层一层
分治
分治:将一个难以解决的大问题分割成一些规模较小的相同的问题,以便各个击破,即份分而治之
分治法使用的场景
-
该问题的规模缩小到一定程度就可以容易的解决;
-
该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
-
利用该问题分解出子问题的解,可以合并为该问题的解;
-
该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题;
分治与递归像是一堆孪生兄弟,经常同时应用在算法设计中
递归
下面用一个简单的斐波那契数列(Fibonacci)来为大家演示一下递归算法
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家莱昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)
C++实现
#include<bits/stdc++.h>
using namespace std;
//递归调用fibonacci函数
int fibonacci(int n){
//如果小于1则结束递归直接返回
if(n<=1){
return 1;
}
return fibonacci(n-1)+fibonacci(n-2);
}
int main(){
int n;
int sum;
while(cin>>n&&n!=-1){
sum=fibonacci(n);
cout<<"值:"<<sum<<endl;
}
}
java实现
package 递归与分治;
import java.util.Scanner;
public class Fibonacci2 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int sum=fibonacci(n);
System.out.println("值:"+sum);
}
static int fibonacci(int a){
if(a<=1){
return 1;
}
return fibonacci(a-1)+fibonacci(a-2);
}
}
正整数n的划分
题目描述:
有一个正整数 n,如果存在 n1 + n2 + … + nk = n (nk > 0),则称 {n1, n2, …, nk} 为正整数 n 的一个划分
问正整数 n 一共有多少个划分?
解题思路
(1) 当 n == 1 或者 m == 1 的时候,f(n, m) = 1
(2) 当 n == m 时,f(n, m) = f(n, m - 1) + 1
因为在 n 的所有划分中,最大加数为 n 时,只有一种划分,即 {n}
所以,f(n, m) 就等于最大加数为 m - 1 的划分数加 1
(3) 当 n < m 时,f(n, m) = f(n, n)
因为在 n 的所有划分中,最大加数只能小于等于 n
(4) 当 n > m 时,f(n, m) = f(n, m - 1) + f(n - m, m)
f(n, m - 1) 为最大加数小于等于 m - 1 的划分数
当最大加数为 m 时,那么每个划分序列有了一个 m,还差 n - m
就相当于是 n - m 有多少个最大加数小于等于 m 的划分数,即 f(n - m, m)
这两部分之和就等于 f(n, m)
c++实现
#include<bits/stdc++.h>
using namespace std;
int IntegerDivsion(int n,int m){
if(n==1||m==1){
return 1;
}
if(n<1||m<1){
return 0;
}
if(n<m){
return IntegerDivsion(n,n);
}
if(n==m){
return IntegerDivsion(n,m-1)+1;
}
if(n>m){
return IntegerDivsion(n,m-1)+IntegerDivsion(n-m,m);
}
}
int main(){
//要拆解的整数
int n;
//最大加数
int m;
cin>>n;
cin>>m;
//结果
int sum;
sum=IntegerDivsion(n,m);
cout<<sum;
}
分治
分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且原生问题相同,递归的解决这些子问题,
然后将各个子问题的解合并并得到原问题的解
最常见的分治是二分,而且是均分。理论研究指出,各个子问题的规模均衡时,算法效率最高。分治法的实现算法往往是递归算法。
下面来实现一下二分查找
题目链接:https://leetcode-cn.com/problems/binary-search/
#include<iostream>
using namespace std;
int search(int* nums, int numsSize, int target){
//left=0开始
int left=0;
//right从最高处开始
int right=numsSize-1;
while(left<=right){
int middle=(right+left)/2;
if(target==nums[middle]){
return middle;
}
else if(target>nums[middle]){
left=middle+1;
}
else{
right=middle-1 ;
}
}
return -1;
}
int main(){
int a[6]={
-1,0,3,5,9,12};
int target ;
cin>>target;
int result=search(a,6,target);
cout<<"下标:"<<result<<endl;
return 0;
}