递归

  1. 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型
  2. 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出
  3. 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程
  4. 将每一步封装好,抽象成一个行动或者处理,然后递归调用,并设定终止条件(汉诺塔 —— 将每一步设定为将当前所有小盘放在2号柱上,将最大的盘放在3号柱上,再将所有小盘放到1号柱上。 终止条件 —— 只有1个盘时,直接放在3号柱上

汉诺塔


该游戏有3个柱子和一组不同大小的圆盘,柱子从圆盘的中心穿过。游戏开始时,所有圆盘叠放在左侧第一个柱子上,游戏的目标是将所有的圆盘从第一个柱子移动到第三个柱子,同时遵守以下规则:

  1. 除了被移动时,所有圆盘都必须放在柱子上
  2. 一次只能移动一个圆盘
  3. 圆盘不能放置在比它小的圆盘上面
#include <bits/stdc++.h>
using namespace std;
int step;
void move(int n,char A,char B,char C){if(n==1){step++;cout<<"["<<step<<"]move 1# from "<<A<<" to "<<C<<endl;}else{move(n-1,A,C,B);cout<<"["<<step<<"]move "<<n<<"# from "<<A<<" to "<<B<<endl;step++;move(n-1,B,A,C);}
}
int main(){int n;cout<<"请输入block数n:"<<endl;cin>>n;move(n,'A','B','C');return 0;
}

[NOIP2001]求先序排列

题目描述

给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,长度 ≤ 8)。

输入描述

1行,表示一棵二叉树的先序

示例一
输入

BADC
BDCA

输出

ABCD

思路

  • 先搞清楚 先序 (根左右)、中序(左根右) 、后序(左右根)
  • 由题意,显而易见——第2行的输入的最后一个字母就是根
  • 然后根据 找到第1行输入的 的位置,就可以分出左子树和右子树,然后递归
  • 对于后序排列中的右子树,根据 的位置找出来,然后递归
  • 简而言之——将传入函数的树分成左子树和右子树,进行递归即可

题解

#include<bits/stdc++.h>
using namespace std;
void priority(string s1,string s2){if(s1=="\0"||s2=="\0")return;char root=s1.find(s2[s2.length()-1]);cout<<s1[root];priority(s1.substr(0,root), s2.substr(0,root));priority(s1.substr(root+1), s2.substr(root,s2.size()-1-root));
}int main(){string s1,s2;cin>>s1>>s2;priority(s1,s2);
}

分治

对于一个规模为n的问题,若该问题可以容易的解决(比如规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解决这些子问题,然后将各个子问题的解合并得到原问题的解
如果原问题可以分割成k个子问题, 1 < k < = n 1<k<=n 1<k<=n,且这些子问题均可解并且利用这些子问题的解求出原问题的解,那么分治方法就是可行的。由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归经常同时应用在算法设计之中

使用

  • 该问题的规模缩小到一定的程度就可以容易的解决
  • 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质
  • 利用该问题分解出的子问题的解可以合并为该问题的解
  • 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题

第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条,而不具备第三条特征,则可以考虑使用贪心法或者动态规划法
第四条关系到分治法的效率,如果各个子问题是不独立的则分治法要做寻多不必要的工作,重复的解决公共的子问题,此时虽然可用分治法,但一般使用动态规划法较好

步骤

  • 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题
  • 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题

[NOIP2004]FBI树

题目描述

我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。
FBI树是一种二叉树[1],它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
(1) T的根结点为R,其类型与串S的类型相同;
(2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历[2]序列。

[1] 二叉树:二叉树是结点的有限集合,这个集合或为空集,或由一个根结点和两棵不相交的二叉树组成。这两棵不相交的二叉树分别称为这个根结点的左子树和右子树。 [2] 后序遍历:后序遍历是深度优先遍历二叉树的一种方法,它的递归定义是:先后序遍历左子树,再后序遍历右子树,最后访问根。

输入描述

第一行是一个整数N(0 <= N <= 10)
第二行是一个长度为2N的“01”串。

输出描述

一个字符串,即FBI树的后序遍历序列。

示例一
输入

3
10001011

输出

IBFBBBFIBFIIIFF

备注

对于40%的数据,N <= 2;
对于全部的数据,N<= 10。

思路

  • 分治——将待处理的字符串分为前后两段
  • 递归——分成前后两段使用递归算法继续分,直到到达题目所设定的要求(s.length()>1)
  • 这道题不用太在意先序后序这些,读懂题目就会发现没涉及到
#include<bits/stdc++.h>
using namespace std;
char FBI(string s){if(s.length()>1){cout<<FBI(s.substr(0,s.length()/2));cout<<FBI(s.substr(s.length()/2,s.length()));}if(s==string(s.length(),'0')) return 'B';if(s==string(s.length(),'1')) return 'I';else return 'F';
}
int main(){int n;string s;cin>>n>>s;cout<<FBI(s);
}

表达式计算4

题目描述

给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值
数据可能会出现括号情况,还有可能出现多余括号情况
数据保证不会出现≥ 231的答案
数据可能会出现负数情况

输入描述

仅一行,即为表达式

输出描述

仅一行,既为表达式算出的结果

示例一
输入

(2+2)^(1+1)

输出

16

备注

表达式总长度≤30

思路

  • 首先,由题意易知,需要进行递归和分治,将操作符两边的数进行分治、递归
  • (雨巨告诉我们,表达式计算用递归最不容易出错)并且应该以栈的思想去解决表达式计算,以先进后出的顺序来解决。同于我们平常计算先算乘方、乘除、加减,应该是先见到乘方就对乘方进行计算(在计算过程中再递归)。
  • 剩下的具体写在代码注释里

题解

#include<bits/stdc++.h>
using namespace std;
string s;
int num(int l,int r){                     //没什么好说的,就是将字符串变成数字int ans=0;for(int i=l; i<=r; i++){ans*=10;ans+=s[i]-'0';}return ans;
}
int solve(int l,int r){int pos1=-1,pos2=-1,pos3=-1;int cnt=0;if(l>r)return 0;if(l==r)return s[l]-'0';for(int i=l; i<=r; i++){                              //对字符串相应的区间遍历if(s[i]=='(')cnt++;if(s[i]==')')cnt--;if(cnt==0){if(s[i]=='+'||s[i]=='-')pos1=i;         if(s[i]=='*'||s[i]=='/')pos2=i;if(s[i]=='^')pos3=i;}}if(pos1==-1&&pos2==-1&&pos3==-1){         //算式在括号里或者是只有数字if(cnt>0&&s[l]=='(')return solve(l+1,r);else if(cnt<0&&s[r]==')')return solve(l,r-1);else if(cnt==0&&s[l]=='('&&s[r]==')')return solve(l+1,r-1);else return num(l,r);}if(pos1>=0){                      //这里的判断顺序是加减、乘除、乘方——对应到计算顺序实际乘方、乘除、加减。因为上一个判断已经解决了括号的情况,所以在此的算式都是无需考虑括号的。if(s[pos1]=='+')return solve(l,pos1-1)+solve(pos1+1,r);else return solve(l,pos1-1)-solve(pos1+1,r);}else if(pos2>=0)if(s[pos2]=='*')return solve(l,pos2-1)*solve(pos2+1,r);else return solve(l,pos2-1)/solve(pos2+1,r);else if(pos3>=0)return pow(solve(l,pos3-1),solve(pos3+1,r));else return 0;
}
int main(){cin>>s;cout<<solve(0, s.length()-1);
}

华华教月月做数学

题目描述

找到了心仪的小姐姐月月后,华华很高兴的和她聊着天。然而月月的作业很多,不能继续陪华华聊天了。华华为了尽快和月月继续聊天,就提出帮她做一部分作业。
月月的其中一项作业是:给定正整数A、B、P,求AB\mod P的值。华华觉得这实在是毫无意义,所以决定写一个程序来做。但是华华并不会写程序,所以这个任务就交给你了。
因为月月的作业很多,所以有T组询问。

输入描述

第一行一个正整数T表示测试数据组数。
接下来T行,每行三个正整数A、B、P,含义如上文。

输出描述

输出T行,每行一个非负整数表示答案。

示例
输入

2
2 5 10
57284938291657 827493857294857 384729583748273

输出

2
18924650048745

备注

1≤T≤103,1≤A,B,P≤1018

思路

  • 看完题目,很容易发现,题目逻辑很简单,但是考察的地方在于时间复杂度上和数据类型的最大容量
  • 像这道题,易知,是肯定不可以直接用pow和普通乘法的
  • 考虑快速幂、加法模拟乘法
  • 快速幂
  • 加法模拟乘法:求7* 5——
    n=5的二进制是101,
    此时n为奇数,则ans=ans+tmp;tmp=tmp+tmp;n右移一位;(ans=0+7,tmp=7* 2)
    此时n为偶数,则直接tmp=tmp+tmp;n右移一位;(ans=7,tmp=7* 4)
    此时n为奇数,则ans=ans+tmp;tmp=tmp+tmp;n右移一位;(ans=7+7* 4,tmp=7*8)

题解

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mul(ll a,ll b, ll mod){          //快速乘法,结构和快速幂相似,就是ans和tmp由乘法变成加法ll ans=0;while(b){if(b&1) ans=(ans+a)%mod;    //if(b&1)用来判断是否为奇数a=(a+a)%mod;b>>=1;}return ans;
}
ll pow(ll a,ll b,ll mod){ll ans=1;while(b){if(b&1) ans=mul(ans,a,mod);a=mul(a,a,mod);b>>=1;}return ans;
}
int main(){int t;ll a,b,mod;scanf("%d",&t);while(t--){cin>>a>>b>>mod;cout<<pow(a,b,mod)<<endl;}
}

递归、分治算法刷题笔记相关推荐

  1. 一夜登顶GitHub!字节内网数据结构与算法刷题笔记,看完直呼卧槽

    网络上流传着一句段子"程序员两条腿,一条是算法,一条是英文,想跑的更远,这两条腿都不能弱".英文,我们暂且不谈,我们先来谈谈算法. 算法之难,在于将精巧的逻辑,通过合适的数据结构, ...

  2. 深度优先搜索dfs算法刷题笔记【蓝桥杯】

    其实网上已经有不少dfs的算法笔记,但我之所以还再写一篇,主要是因为我目前见到的笔记,都有些太偏向理论了. 对于基础薄弱的或是没有基础的人(like me),有点不合适,因为看了,也不能说自己会了. ...

  3. Github最强算法刷题笔记.pdf

    资料一 昨晚逛GitHub,无意中看到一位大佬(https://github.com/halfrost)的算法刷题笔记,感觉发现了宝藏!有些小伙伴可能已经发现了,但咱这里还是忍不住安利一波,怕有些小伙 ...

  4. 发现一位大佬的算法刷题笔记PDF

    昨晚逛GitHub,无意中看到一位大佬(https://github.com/halfrost)的算法刷题笔记,感觉发现了宝藏!有些小伙伴可能已经发现了,但咱这里还是忍不住安利一波,怕有些小伙伴没有看 ...

  5. 经典算法刷题笔记pdf

    昨晚逛GitHub,无意中看到一位大佬(https://github.com/halfrost)的算法刷题笔记,感觉发现了宝藏!有些小伙伴可能已经发现了,但咱这里还是忍不住安利一波,怕有些小伙伴没有看 ...

  6. 【c++算法刷题笔记】——洛谷2

    1. 洛谷练习--P1579 哥德巴赫猜想(升级版) 题目描述: 现在请你编一个程序验证哥德巴赫猜想. 先给出一个奇数n,要求输出3个质数,这3个质数之和等于输入的奇数. 输入格式: 仅有一行,包含一 ...

  7. 字节大老耗时5年总结的算法刷题笔记(全彩漫画版)

    前言 王国维先生在<人间词话>中写道:古今之成大事业.大学问者,必经过三种境界:"昨夜西风凋碧树.独上高楼,望尽天涯路."此第一境也."衣带渐宽终不悔,为伊消 ...

  8. 字节跳动算法无敌的惊天秘密!字节内部不传之秘:1000页算法刷题笔记(附源码可直接运行)

    小编的一位同事在校期间连续三年参加ACM-ICPC竞赛.从参赛开始,原计划每天刷一道算法题,实际上每天有时候不止一题,一年最终完成了 600+: 凭借三年刷题经验,他在校招中很快拿到了各大公司的off ...

  9. 阿里内部不传之秘:1000页算法刷题笔记

    曾经的一位同事在校期间连续三年参加ACM-ICPC竞赛.从参赛开始,原计划每天刷一道算法题,实际上每天有时候不止一题,一年最终完成了 600+: 凭借三年刷题经验,他在校招中很快拿到了各大公司的off ...

最新文章

  1. SnackbarUtilDemo【Snackbar的封装类】
  2. 通过IDoc来实现公司间STO场景中外向交货单过账后自动触发内向交货单的功能 - Part I
  3. 盖茨发文谈如何实现零碳目标 称看好电动车未来
  4. shell编程基础-简述
  5. mysql常用操作记录
  6. 最后一周!导师推荐的转录组和可视化学习捷径
  7. 今天装了个GPS时钟
  8. 鲲鹏迁移第一批吃螃蟹的人,践行技术国际化
  9. textbox根据内容自动调整高度
  10. 开源的“底线”在哪里?
  11. Linux从入门到精通——数据库
  12. Asp.net中文件的上传和下载(视频教程)
  13. vue 原生js写车牌号键盘
  14. python画十字_Python解决十字消除棋
  15. 项目Kick Off 我们应该做什么?
  16. ie主页被劫持怎么办 解决浏览器主页劫持方法
  17. 三、共阳数码管的静态显示
  18. A. 【UNR #2】积劳成疾
  19. 软件工程自测题及答案
  20. MySQL入门:数据库是什么 | SQL是什么 | MySQL是什么

热门文章

  1. 张量(Tensor)操作
  2. Partial Class
  3. STM32的USB例程JoyStickMouse代码分析
  4. html 图片纵向拉伸,css如何让图片拉伸?
  5. Prince and Princess HDU - 4685
  6. 怎么看外文文献的影响因子_sci 上的论文影响因子怎么看
  7. R型电焊机电源变压器的特点都有哪些?
  8. SpringCloud OpenFeign 整合 logbook 实现链路日志
  9. 华为畅享6s可以升级鸿蒙,【华为畅享6S评测】华为畅享6S评测:颜值高又好用的千元机就是它了-中关村在线...
  10. 可能不能吃的食物-为自己记录一下