【王道机试指南学习笔记】第八章 递归与分治

【Nan's 王道机试指南学习笔记】第八章 递归与分治

  • 8.1 递归策略
    • 重点提醒
    • 递归条件
    • 题目练习
      • 例题8.1 n的阶乘(清华复试)
      • 例题8.2 汉诺塔Ⅲ
      • 习题8.1 杨辉三角形(西北工业)
      • 习题8.2 全排列(北大复试)
  • 8.2 分治法 Divide&Conquer
    • 重点提醒
    • 题目练习
      • 例题8.3 Fibonacci(上交复试)
      • 例题8.4 二叉树(北大复试)

8.1 递归策略

重点提醒

递归——函数直接 / 间接调用自身的一种方法。把复杂问题层层转化为与原问题相似但规模较小的问题来求解。

少量程序,实现多次计算,大大减少代码量。

递归条件

1)子问题必须与原始问题相同,且规模更小。
2)不能无限制地调用本身,必须有一个递归出口。

题目练习

例题8.1 n的阶乘(清华复试)

牛客网网址:https://www.nowcoder.com/questionTerminal/f54d8e6de61e4efb8cce3eebfd0e0daa
(n的阶乘 = n * n-1的阶乘,0的阶乘是最底层子问题,子问题不可分解且易于求解)

#include 
#include 

using namespace std;
long long Cheng(int n){
    if(n == 0) return 1;//递归出口
    else return n*Cheng(n-1);//递归调用
}
int main(){
    int n;
    while(cin>>n){
        cout<<Cheng(n)<<endl;
    }
    return 0;
}

例题8.2 汉诺塔Ⅲ

题目:
在这里插入图片描述
思路:
【王道机试指南学习笔记】第八章 递归与分治_第1张图片

#include 

using namespace std;
long long Function(int n){
    if(n == 1) return 2;//递归出口
    else return 3*Function(n-1)+2;//递归调用
}
int main(){
    int n;
    while(cin>>n){
        cout<<Function(n)<<endl;
    }
    return 0;
}

习题8.1 杨辉三角形(西北工业)

牛客网网址:https://www.nowcoder.com/questionTerminal/ef7f264886a14fdf8a6ed3ac008a23c8
还蛮简单 数学逻辑会即可

#include 

using namespace std;
int YangHui(int i,int j){
    if(j==1 || j==i) return 1;//递归出口
    else return YangHui(i-1,j-1)+YangHui(i-1,j);//递归调用
}
int main(){
    int n;
    while(cin>>n){
        for(int i=2; i<=n; i++) {//i从1开始 才会打印出第一行的1 但是OJ答案没1
            for(int j=1; j<=i; j++) {
                cout<<YangHui(i, j)<<" ";
            }
            cout<<endl;
        }
    }
    return 0;
}

习题8.2 全排列(北大复试)

牛客网网址:https://www.nowcoder.com/questionTerminal/5632c23d0d654aecbc9315d1720421c1
再好好看看!

#include
#include
#include
using namespace std;

const int maxn = 100;//P为当前排列,rec记录x是否已经在result中
int n;//字符串长度
int rec[maxn]={false};//当前处理排列的index位
char result[maxn];//储存全排列结果的数组

void Func(int index,char str[]){
    if(index==n){//递归边界
        for (int i = 0; i <n; ++i){
            printf("%c", result[i]);//输出当前排列
        }
        printf("\n");
        return;
    }
    for (int x = 0; x <n; ++x){//枚举1~n,试图将x填入result【index】
        if (rec[x]==false){//如果x不在p[0]~p[index-1]中
            result[index]=str[x];//把str[x]加入当前排列
            rec[x]=true;//记x已经在p中
            Func(index+1,str);//处理排列的index+1位
            rec[x]=false;//已处理完p[index]为x的子问题,还原状态
        }
    }
}
int main(){
    char str[maxn];
    while(scanf("%s",str)!=EOF){
        n=strlen(str);
        sort(str,str+n);//将原始数组进行大小排序 升序
        Func(0,str);
        printf("\n");
    }
    return 0;
}

8.2 分治法 Divide&Conquer

重点提醒

分治——复杂问题拆为2个及多个子问题,每个问题相互独立且与原问题相似。
原问题的解 == 子问题解的合并。
分治法的步骤:
①分
②治:逐个击破小规模子问题
③合:合并已解决的小问题
【王道机试指南学习笔记】第八章 递归与分治_第2张图片

题目练习

例题8.3 Fibonacci(上交复试)

牛客网网址:https://www.nowcoder.com/questionTerminal/17ad6908e36a49f4b06ea96936e8bb25

#include
using namespace std;

int Fibonacci(int n){
    if(n==1 || n==0){//递归出口
        return n;
    }
    else return Fibonacci(n-2)+Fibonacci(n-1);
}
int main(){
    int n;
    while(cin>>n){
        cout<<Fibonacci(n)<<endl;
    }
    return 0;
}

例题8.4 二叉树(北大复试)

牛客网网址:https://www.nowcoder.com/practice/f74c7506538b44399f2849eba2f050b5
转为二进制 通过位数确认的写法还不错

#include 
using namespace std;
// GetBit函数 137 = 2^7 + 2^3 + 2^0 写成2进制数:10001001
// 确定n的二进制数形式的第i位是1还是0
int GetBit(int n,int i)
{
    return (n>>i)&1;//整数n右移i位
}
void Ex(int n)
{
    bool first=true;
    for(int i=15; i>=0; --i)
    {
        if(GetBit(n,i))
        {
            if(!first)cout<<"+";
            else first=false;
            if(!i)cout<<"2(0)";
            else if(i==1)cout<<"2";
            else
            {
                cout<<"2(";
                Ex(i);
                cout<<")";
            }
        }
    }
}
int main(){
    int n;
    while(cin>>n){
        Ex(n);
        cout<<endl;
    }
}

你可能感兴趣的:(王道机试指南,学习笔记,算法)