遞歸筆試題


1、一個樓梯有20級,每次走1級或是2級,從底走到頂一共有多少中走法?
算法:
    設 n 是階數,f(n) 是上 n 階的不同走法數,則第一步可以走一階或者是兩階,
    那么這三種情況下剩余的階數分別為 n-1、n-2,
    所以 f(n) = f(n-1) + f(n-2)。

//遞歸解法
int solution1(int n)
{
    if(n == 0 || n == 1) return 1;
    else return solution1(n-1) + solution1(n-2);
}

//非遞歸解法
int f[100];
int solution2(int n)
{
    f[0] = 1;
    f[1] = 1;
    for(int i=2; i<=n; ++i)
      f[i] = f[i-1] + f[i-2];
    return f[n];
}

2、質因數分解:得到num的所有質因數

void prime_number(int num, int n)
{
    if(num > n)
    {
        while(num % n)  n++; //找到一個質因數
        num /= n; //除以這個質因數
        cout<<n<<endl; //打印這個質因數
        prime_number(num,n);
    }
}
int main()
{
    int n = 1001;
    prime_number(n,2);
    return 0;
}

3、不用任何中間變量,如何獲取字符串的長度

int my_strlen(const char* str)
{
    if(*str == '\0') return 0;
    else return my_strlen(str+1)+1;
}

不用任何中間變量,以遞歸反序輸出一個字符串:

void reverse(const char *p)
{
    if(*p == '\0') return;
    reverse(p+1);
    printf("%c",*p);
}

4、全排列和全組合

#include <iostream>
using namespace std;

template <class Type>
void permute(Type a[], int start, int end)
{
    if(start == end)
    {
        for(int i = 0; i <= end; ++i)
        {
            cout<<a[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        for(int i = start; i <= end; ++i)
        {
            swap(a[i],a[start]);
            permute(a,start+1,end);
            swap(a[i],a[start]);
        }
    }
}

template <class Type>
void combine(Type a[], bool b[], int start, int end)
{
    if(start > end)
    {
        for(int i = 0; i <= end; ++i)
        {
            if(b[i])
                cout<<a[i]<<" ";
        }
        cout<<endl;
    }
    else
    {
        b[start] = true;
        combine(a,b,start+1,end);
        b[start] = false;
        combine(a,b,start+1,end);
    }
}

int main()
{
    int p[3]={1,2,3};
    int N = 3;
    cout<<"permute:"<<endl;
    permute(p,0,N-1);
    cout<<"combine:"<<endl;
    bool b[3];
    combine(p,b,0,N-1);

    return 0;
}

全組合還有一個有趣的解法:可以構照一個長度為n(字符串的長度)的01字符串(或二進制數)表示輸出結果中最否包含某個字符,比如:對於字符串“abc”,"001"表示輸出結果中不含字符a、b,只含c,即輸出結果為c,而"101",表示輸出結果為ac。原題就是要求輸出"001"到"111"這2^n–1個組合對應的字符串。
參考:http://www.cnblogs.com/luxiaoxun/archive/2012/08/08/2628153.html

5、給出一個集合,如{1, 2, 3, 4},打印出該集合的所有子集 分析一下問題,子集是指取原集合中的任意多個元素,轉化一下問題,就是對於原集合中的任何一個元素,都有兩個選擇,包含或者不包含,所以對於n個元素的集合,其子集數為:2*2*2... = 2^n,去掉空集就是2^n-1個。那么可以得出其遞歸算法,本題實質上和打印字符串的所有組合是一樣的。

void Recursive_Subsets(int* a, bool* b, int start, int end) 
{ 
    if(start <= end) 
    {
        b[start] = true; // pick the a[start]
        Recursive_Subsets(a, b, start+1, end); 

        b[start] = false; // not pick the a[start] 
        Recursive_Subsets(a, b, start+1, end); 
    } 
    else
    { 
        for(int i = 0; i <= end; i++) 
        { 
            if (b[i]) cout << a[i]; 
        } 
        cout << endl; 
    }
} 

void PrintAllSubsets(int* a, int n) 
{ 
    bool* b = new bool[n]; 
    Recursive_Subsets(a, b, 0, n-1); 
    delete b; 
}

6、電話號碼對應的字符組合

題目:在電話或者手機上,一個數字如2對應着字母ABC,7對應着PQRS。那么數字串27所對應的字符的可能組合就有3*4=12種(如AP,BR等)。現在輸入一個3到11位長的電話號碼,請打印出這個電話號碼所對應的字符的所有可能組合和組合數。

#include<iostream>
using namespace std;

const char* letter[10]={"","","ABC","DEF","GHI","JKL","MNO","PQRS","TUV","WXYZ"};
const int num[10]={0,0,3,3,3,3,3,4,3,4};
char input[20];
char output[20];

void solve(int p,int len)
{
    if(p == len)
    {
        output[len] = '\0';
        cout<<output<<endl;
        return;
    }
    int i;
    for(i=0; i<num[input[p]]; i++)
    {
        output[p] = letter[input[p]][i];
        solve(p+1,len);
    }
}

int main()
{
    scanf("%s",input);
    len = strlen(input);
    
    int total = 1;
    for(int i=0; i<len; i++) 
    {
        input[i] -= '0';
        total *= num[input[i]];
    }
    solve(0,len);

    cout<<"The total num of combination is "<<total<<endl;
    return 0;
}

7、Coin Chagne:硬幣找零問題

硬幣找零問題:給定一個正整數N,和一個正整數集合S,集合中的每個元素都有無限個,如何選定集合中的元素組合使其和為N For example, for N = 4, S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}.

遞歸解法:假設集合S中的元素的順序是遞增的,則: C(N,M),表示從M個元素選中若干個滿足和為N的解法個數,則C(N,M)=C(N,M-1)+C(N-S[M-1],M-1)
C(N,M)=1, N=0
C(N,M)=0, N<0
C(N,M)=0, N>=1,M<=0

int Count(int N, int *s, int M)
{
    if(N == 0) return 1;
    if(N < 0) return 0;
    if(N >= 1 && M <= 0) return 0;
    return Count(N,s,M-1)+Count(N-s[M-1],s,M-1);
}

最少硬幣找零問題:給定一個正整數N,和一個正整數集合S,集合中的每個元素都有無限個,如何選定最少的集合中元素,使其和為N For example, for N = 4, S = {1,2,3}, there are two solutions: {2,2},{1,3}.

遞歸解法:假設集合S中的元素的順序是遞增的,C(N,M),表示從M個元素選中若干個滿足和為N的解法個數,則: C(N,M)=min(C(N,M-1),C(N-S[M-1],M-1))+1

int minCount(int N, int *s, int M)
{
    if(N == 0) return 1;
    if(N < 0) return 0;
    if(N >= 1 && M <= 0) return 0;
    return min(Count(N,s,M-1),Count(N-s[M-1],s,M-1))+1;
}

8、輸入兩個整數 n 和 m,從數列1,2,3...n 中隨意取幾個數,使其和等於m ,要求將其中所有的可能組合列出來。

解為:此題等同於整數分解問題,將m分解成n以內的解為:f(n,m),分解成兩個子問題:f(n-1,m-n)和f(n-1,m)

vector<int> vec;
void find_factor(int sum, int n)
{
    if(n <= 0 || sum <= 0)
        return;
    if(sum == n)
    {
        for(vector<int>::iterator iter = vec.begin(); iter != vec.end(); iter++)
            cout << *iter << " + ";
        cout << n << endl;
    }
    vec.push_back(n);
    find_factor(sum-n, n-1);   //放n,n-1個數填滿sum-n
    vec.pop_back();
    find_factor(sum, n-1);     //不放n,n-1個數填滿sum
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM