Bootstrap

递归算法介绍(C++)

递归算法常见案例介绍(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;
    }
};
;