递归算法常见案例介绍(C++)
1.反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
class Solution {
public:
void reverse(vector<char>&s,int i)
{
int l=s.size();
if(i>=l/2) return; //设置返回条件
char temp=s[i];
s[i]=s[l-1-i];
s[l-1-i]=temp;//原地交换前后两元素,下标和为l-1
reverse(s,i+1);//进入下一个递归函数
}
void reverseString(vector<char>& s) {
reverse(s,0);
}
};
2.两两交换链表中的节点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
例:1->2->3->4 变为2->1->4->3
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head==NULL||head->next==NULL) return head;
ListNode* p=head->next;
head->next=swapPairs(p->next);
p->next=head;
return p;
}
};
3.杨辉三角形
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。在杨辉三角中,每个数是它左上方和右上方的数的和。
例:
输入: 5
输出:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>>res;
res.push_back({{1}});
for(int i=1;i<numRows;i++)
{
vector<int>tmp(i+1,1);
for(int j=1;j<i;j++)
{
int ans=res[i-1][j-1]+res[i-1][j];
tmp[j]=ans;
}
res.push_back(tmp);
}
return res;
}
};
给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。(K从0开始)
//1.全部计算
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<vector<int>>C(rowIndex+1);
for(int i=0;i<=rowIndex;i++)
{
C[i].resize(i+1);
C[i][0]=1;
C[i][i]=1;
for(int j=1;j<i;j++)
{
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
}
return C[rowIndex];
}
};
//2.滚动数组优化
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int>pre,cur;
for(int i=0;i<=rowIndex;i++)
{
cur.resize(i+1);
cur[0]=1,cur[i]=1;
for(int j=1;j<i;j++)
{
cur[j]=pre[j-1]+pre[j];
}
pre=cur;
}
return cur;
}
};
//3.一维数组
class Solution {
public:
vector<int> getRow(int rowIndex) {
vector<int>Row(rowIndex+1);
Row[0]=1;
for(int i=1;i<=rowIndex;i++)
{
for(int j=i;j>0;j--)
{
Row[j]+=Row[j-1];
}
}
return Row;
}
};
4.反转链表
反转一个单链表。
例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
//迭代法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL) return NULL;
ListNode* pre=NULL;
ListNode* cur=head;
ListNode* nextcur=cur->next;
while(cur->next)
{
nextcur=cur->next;
cur->next=pre;
pre=cur;
cur=nextcur;
}
cur->next=pre;
return cur;
}
};
//迭代法简洁写法
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur=NULL;
ListNode* pre=head;
while(pre)
{
ListNode* t=pre->next;
pre->next=cur;
cur=pre;
pre=t;
}
return cur;
}
};
//递归法求解
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL||head->next==NULL) return head;
ListNode* ret=reverseList(head->next);
head->next->next=head;
head->next=NULL;
return ret;
}
};
5.斐波那契数列
斐波那契数,通常用 F(n) 表示,形成的序列称为斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
//自上而下简单递归,引入大量重复计算
class Solution {
public:
int fib(int n) {
if(n<=1) return n;
int res;
res=fib(n-1)+fib(n-2);
return res;
}
};
//自下而上迭代
class Solution {
public:
int fib(int n) {
if(n<=1) return n;
int f0=0,f1=1;
int f;
for(int i=2;i<=n;i++)
{
f=f0+f1;
f0=f1;
f1=f;
}
return f;
}
};
//建立unordered_map,略去重复计算
class Solution {
public:
unordered_map<int,int>map;
int fib(int n) {
if(n<=1) return n;
if(map.count(n)) return map[n];
int a=fib(n-1);
map[n-1]=a;
int b=fib(n-2);
map[n-2]=b;
int res=fib(n-1)+fib(n-2);
map[n]=res;
return res;
}
};
6.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?注意:给定 n 是一个正整数。
//简单递归
class Solution {
public:
int climbStairs(int n) {
if(n<=0) return 0;
if(n<=3) return n;
int res;
res=climbStairs(n-1)+climbStairs(n-2);
return res;
}
};
//简单迭代,也可称作是动态规划,自底向上
class Solution {
public:
int climbStairs(int n) {
if(n<=0) return 0;
if(n<=3) return n;
int a=2,b=3;
int c;
int res;
for(int i=4;i<=n;i++)
{
res=a+b;
a=b;
b=res;
}
return res;
}
};
//和斐波那契数列基本一样
7.求二叉树的最大深度
给定一个二叉树,找出其最大深度。二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。说明: 叶子节点是指没有子节点的节点。
//简单的层序遍历求解
class Solution {
public:
int maxDepth(TreeNode* root) {
//层序遍历
if(root==NULL) return 0;
queue<TreeNode*>q;
q.push(root);
int depth=0;
int count=0;
while(!q.empty())
{
int l=q.size();
count++;
for(int i=0;i<l;i++)
{
TreeNode* node=q.front();
q.pop();
if(node->left) q.push(node->left);
if(node->right) q.push(node->right);
}
}
return count;
}
};
//递归法求解,非常简单
class Solution {
public:
int maxDepth(TreeNode* root) {
//递归求解
if(root==NULL) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,x^n)。
//递归快速幂算法,时间复杂度O(log(n))次
class Solution {
public:
double fastPow(double x,long long int n)//这里的n为正数
{
double res,half;
if(n==0) return 1.0;
half=fastPow(x,n/2);
if(n%2==0)
{
return half*half;
}
else
{
return half*half*x;
}
}
double myPow(double x, long long int n) {
if(x==0&&n==0) return 0;
if(n==0) return 1;
if(n==1) return x;
if(n<0)
{
x=1/x;
n=-n;
}
return fastPow(x,n);
}
};
8.合并两个升序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
例:输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL||l2==NULL) return l1==NULL?l2:l1;
while(l1&&l2)
{
if(l1->val<l2->val)
{
if(l1->next==NULL) l1->next=l2;
else
{
l1->next=mergeTwoLists(l1->next,l2);
}
return l1;
}
else
{
if(l2->next==NULL) l2->next=l1;
else
{
l2->next=mergeTwoLists(l1,l2->next);
}
return l2;
}
}
return NULL;
}
};
9.第K个语法符号
在第一行我们写上一个 0。接下来的每一行,将前一行中的0替换为01,1替换为10。给定行数 N 和序数 K,返回第 N 行中第 K个字符。(K从1开始)
第一行: 0
第二行: 01
第三行: 0110
第四行: 01101001
class Solution {
public:
int kthGrammar(int N, int K) {
//貌似前一部分与上一行一样,后面部分为前面部分取反,故只要知道上一行即可
int res;
if(K==1) return 0;
if(K==2) return 1;
if(K<=pow(2,N-2))
{
res=kthGrammar(N-1, K);
}
else
{
if(kthGrammar(N-1, K-pow(2,N-2))==0) res=1;
else res=0;
}
return res;
}
};
10.不同的二叉搜索树
输入:3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
class Solution {
public:
vector<TreeNode*>helper(int start,int end)
{
vector<TreeNode*>ret;
if(start>end) ret.push_back(NULL);
for(int i=start;i<=end;i++)
{
vector<TreeNode*> left=helper(start,i-1);
vector<TreeNode*> right=helper(i+1,end);
for(auto l:left)
{
for(auto r:right)
{
TreeNode* root=new TreeNode(i);//每次root要重新生成
root->left=l;
root->right=r;
ret.push_back(root);
}
}
}
return ret;
}
vector<TreeNode*> generateTrees(int n) {
vector<TreeNode*>res;
if(n<=0) return {};
res=helper(1,n);
return res;
}
};