1. 程式人生 > >隨手練——幾個遞歸小題目

隨手練——幾個遞歸小題目

pac roc target 按順序 ima pos void 遞歸 打印

遞歸最重要的兩點:

1.base case(遞歸出口)。必須有某些基本情形,它無需遞歸就能解出。

2.分解 或者 分類。分解成子問題,或者每層遞歸分叉,也就是一個N叉樹模型。

例題:

  • 打印一個字符串的所有子串

分解:按順序每個字母是否打印,分解。

技術分享圖片

base case: 當 pos==length,分解到了最後一步

void process(char *s,int pos,int length,string res) {
    if (pos == length) {
        cout << res << endl;
        return
; } process(s, pos + 1,length,res); process(s, pos + 1, length, res + s[pos]); } int main() { char str[] = "abc"; process(str, 0, 3,""); return 0; }
  • 打印一個字符串的全排列

void process(string s,int n) {
    if (n == s.length()) {
        cout << s << endl;
        return
; } for (int i = n; i < s.length(); i++) { swap(s[i],s[n]); process(s,n+1); } }
  • 給定一個數組,數組中元素能否累加得到 指定值aim

要註意帶返回值的遞歸函數寫法:

bool recur(int *a, int n,int res,int aim,int length) {
    if (n == length || res == aim) {
        return res == aim;
    }
    return
recur(a, n + 1, res + a[n], aim,length)|| recur(a, n + 1, res, aim,length); }
  • 不是所有題目都適合用遞歸

比如:HDU 2018:http://acm.hdu.edu.cn/showproblem.php?pid=2018

兩種解法,雖然遞歸解法要短很多,但是時間上,填表要快很多,因為遞歸會重復計算已經算過的值:

#include <iostream>
using namespace std;
int a[55];
int f(int n) {
    if (n <= 4) return n;
    return f(n - 1) + f(n - 3);
}
int main() {
    int n;
    a[1] = 1; a[2] = 2; a[3] = 3; a[4] = 4;
    for (int i = 5; i < 55; i++) {
        a[i] = a[i - 1] + a[i - 3];
    }
    while (cin >> n) {
        if (n == 0)break;
        cout << a[n]<< endl;
    }
    return 0;
}

隨手練——幾個遞歸小題目