算法处探:递归练习

  • 求两个串的最大公共子序列

    此题要注意子序列和子串的概念。

    假如两个串第一个位置的元素相同,那么只需比较两串剩余的部分的公共子序列长度。

    如果不同,有两种情况:

    ​ 1.比较字串A剔除第一个位置元素与字串B的公共子序列

    ​ 2.比较字串A和字串B剔除第一个位置元素的公共子序列

    取两种情况的最大值。

#include <bits/stdc++.h>
using namespace std;
//求两个串的最大公共子序列
int f(string s1, string s2)
{
    if(s1.size() == 0 || s2.size() == 0)
        return 0;
    if(s1[0] == s2[0])
        return f(s1.substr(1,s1.size()), s2.substr(1,s2.size())) + 1;//剩余部分
    else
        return max(f(s1.substr(1, s1.size()), s2), f(s1, s2.substr(1, s2.size())));
}
int main()
{
    string s1;
    string s2;
    cin>>s1>>s2;
    int k = f(s1, s2);
    cout<<k;
    return 0;
}
  • 在n个球中,任意去取m个(不放回), 求有多少种不同取法

    假设有一个特殊球,此球的状态只有两种:被取到和没有被取到。

    若被取到,那么只需在n-1个球中取m-1个球。

    若没有被取到,需在n-1个球中取m个球。

    #include <bits/stdc++.h>
    using namespace std;
    //在n个球中,任意去除m个(不放回), 求有多少种不同取法
    int f(int n, int m)
    {
        if(n<m)
            return 0;
        if(n==m)
            return 1;
        if(m==0)
            return 1;
    
        return f(n-1,m-1) + f(n-1, m);  // 找一个特殊球
    }
    int main()
    {
        int n, m;
        cin>>n>>m;
        int k = f(n, m);
        cout<<k;
        return 0;
    }
    
    
  • 求n个元素的全排列

    第一个位置n个元素都有可能,所以将第一个位置的元素与后面的每个元素进行交换。

    每交换一次,第一个位置的元素就确定了,然后将剩余的部分也进行全排列,进行同样操作。

    但是注意最后要再交换回来。

    #include <bits/stdc++.h>
    using namespace std;
    //求n个元素的全排列
    void f(string s, int k)
    {
        if(k==s.size())
        {
            cout<<s<<endl;
        }
       for(int i=k;i<s.size();i++)
       {
           char ch = s[k]; s[k] = s[i]; s[i] = ch; // 试探
           f(s, k+1);
           ch = s[k]; s[k] = s[i]; s[i] = ch; // 回溯
       }
    }
    int main()
    {
        string s;
      cin>>s;
        f(s, 0);
        return 0;
    }
    
    
  • 求反转串

    #include <bits/stdc++.h>
    using namespace std;
    //求反转串:如,cba->abc
    string f(string s)
    {
        if(s.length() < 2)
            return s;
        return f(s.substr(1,s.size())) + s[0];
    }
    int main()
    {
        string s;
        cin>>s;
        cout<<f(s);
        return 0;
    }
    
  • 计算杨辉三角第n层的第m个系数

    第m层第n的系数的值等于 第n-1层第m个系数+第n-1层第m-1个系数。

    如果n=0或者m=1,返回1.

    #include <bits/stdc++.h>
    using namespace std;
    //计算杨辉三角第n层的第m个系数,m和n都从0开始
    int f(int n, int m)
    {
        if(m==0)
            return 1;
        if(m==n)
            return 1;
        return f(n-1, m) + f(n-1, m-1);
    }
    int main()
    {
        int n,m;
        cin>>n>>m;
        cout<<f(n, m)<<endl;
        return 0;
    }
    
  • 计算m个A,n个B可以有多少个不同排列

    从第一个位置开始,可能选A,也可能选B。

    如果选A,那么以后的位置需要排列m-1个A和n个B。

    如果选B,以后的位置需要排列n个A和n-1个B。

    #include <bits/stdc++.h>
    using namespace std;
    //计算m个A,n个B可以有多少个不同排列
    int f(int m, int n)
    {
        if(n==0 || m==0)
            return 1;
        return f(m-1, n) + f(m, n-1); 
    }
    int main()
    {
        int m, n;
        cin>>m>>n;
        cout<<f(m, n)<<endl;
        return 0;
    }
    
  • 整数分划问题

    数组a用来保存分划的数

    k是当前的位置

    #include <bits/stdc++.h>
    using namespace std;
    //整数的分划问题
    void f(int n, int a[], int k)
    {
        if(n==0)
        {
            for(int i=0; i<k; i++)
                cout<<a[i]<<" ";
            cout<<endl;
            return ;
        }
    
        for(int i=n; i>0; i--)
        {
            if(k>0 && a[k-1]<i)
                continue;
            a[k] = i;
            f(n-i, a, k+1);
        }
    }
    int main()
    {
        int n;
        cin>>n;
        int a[100];
        f(n, a, 0);
        return 0;
    }
    
    
  • 查账单

    err_sum:错误总金额

    cur_sum:前面元素的累加和

    k:当前要处理的元素位置

    b:对应a中元素是否是漏掉的

    #include <bits/stdc++.h>
    using namespace std;
    //查账单
    //输入第一行是有错的总金额
    //接下来是n,表示将要输入的明细账目的条数
    //再接下来是n行整数,分别表示每笔账目的数目
    //要求输出可能漏掉的金额组合
    
    int n; //账目条数
    void f(int err_sum, int *a, int k, int cur_sum, bool *b)
    {
        if(cur_sum > err_sum)
            return ;
        if(cur_sum == err_sum)
        {
            for(int i=0; i<n; i++)
                if(!b[i])
                    cout<<a[i]<<" ";
            cout<<endl;
            return ;
        }
        if(k >= n)
            return ;
    
        b[k] = false;
        f(err_sum, a, k+1, cur_sum, b); // 不加到错误账单中
    
        b[k] = true;
        cur_sum += a[k];
        f(err_sum, a, k+1, cur_sum, b); // 加到错误账单中
    
        b[k] = false; // 回溯
    }
    int main()
    {
    
        int err_sum;//保存有错的总金额
        int *a;//n条账目明细
        bool *b;
        cin>>err_sum>>n;
        a = new int[n];
        b = new bool[n];
        for(int i=0; i<n; i++)
            cin>>a[i];
        f(err_sum, a, 0, 0, b);
        return 0;
    }
    
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容