常见经典递归总结

排列、组合、子集枚举

Posted by Marlin on August 14, 2025

常见经典递归总结

子集枚举

题目 1 返回字符串的全部字序列

时间复杂度:$O(n*2^n)$(子集枚举+遍历)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
bool st[20];
set<string> set_str;

void dfs(int x, string& str){
    if (x >= str.size()){
        string temp;
        for(int i = 0; i < str.size(); i++){ // 遍历子集
            if (st[i]){
                temp.push_back(str[i]);
            }
        }
        set_str.insert(temp);
        return;
    }

    st[x] = true;
    dfs(x + 1, str); // 选
    st[x] = false;
    dfs(x + 1, str); // 不选
}
vector<string> generatePermutation(string s) {
    dfs(0, s);
    vector<string> ans;
    for(auto it : set_str){
        ans.push_back(it);
    }
    return ans;
}

题目 2 子集 II

时间复杂度:$O(n*2^n)$(子集枚举+遍历)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
bool stat[100]; // 存储状态
set<vector<int>> st;
void dfs(int x, vector<int> &nums) {
    if (x >= nums.size()) {
        vector<int> temp;
        for (int i = 0; i < nums.size(); i++) { // 遍历子集
            if (stat[i]) {
                temp.push_back(nums[i]);
            }
        }
        st.insert(temp);
        return;
    }
    stat[x] = true;
    dfs(x + 1, nums); // 选
    stat[x] = false;
    dfs(x + 1, nums); // 不选
}

vector<vector<int>> subsetsWithDup(vector<int> &nums) {
    vector<vector<int>> ans;
    sort(nums.begin(), nums.end());
    dfs(0, nums);
    for (auto it : st) {
        ans.push_back(it);
    }
    return ans;
}

排列

题目 1 全排列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
vector<vector<int>> ans;
int arr[100];
int st[100];
void dfs(int x, vector<int> &nums) {
    int n = nums.size();
    if (x >= n) {
        vector<int> temp;
        for (int i = 0; i < n; i++) {
            int idx = arr[i];
            temp.push_back(nums[idx]);
        }
        ans.push_back(temp);
        return;
    }
    for (int i = 0; i < n; i++) {
        if (st[i]) {
            continue;
        }
        st[i] = 1;
        arr[x] = i;
        dfs(x + 1, nums);
        st[i] = 0;
        arr[x] = 0;
    }
}
vector<vector<int>> permute(vector<int> &nums) {
    dfs(0, nums);
    return ans;
}

题目 2 全排列 II

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
set<vector<int>> set_vec;
vector<vector<int>> ans;
int arr[100];
bool st[100];

void dfs(int x, vector<int> &nums) {
    int n = nums.size();
    if (x >= n) {
        vector<int> temp;
        for (int i = 0; i < n; i++) {
            int idx = arr[i];
            temp.push_back(nums[idx]);
        }
        set_vec.insert(temp);
        return;
    }
    for (int i = 0; i < n; i++) {
        if (st[i]) {
            continue;
        }
        st[i] = true;
        arr[x] = i;
        dfs(x + 1, nums);
        st[i] = false;
        arr[x] = 0;
    }
}
vector<vector<int>> permuteUnique(vector<int> &nums) {
    dfs(0, nums);
    for (auto it : set_vec) {
        ans.push_back(it);
    }
    return ans;
}

只用递归函数逆序栈

时间复杂度:$O(n^2)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int bottomOut(stack<int> &stk) { // 操作:将栈底元素返回,并保持其它元素顺序不变
    int ans = stk.top();
    stk.pop();
    if (stk.empty()) {
        return ans;
    }
    int last = bottomOut(stk);
    stk.push(ans);
    return last;
}
void reverse(stack<int> &stk) { // 利用操作逆序栈
    if (stk.empty()) {
        return;
    }
    int num = bottomOut(stk);
    reverse(stk);
    stk.push(num);
}

只用递归函数排序栈

时间复杂度:$O(n^2)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int deep(stack<int> &stk) { // 操作:返回栈深度不改变栈状态
    if (stk.empty()) {
        return 0;
    }
    int num = stk.top();
    stk.pop();
    int deep = deep(stk) + 1;
    stk.push(num);
    return deep;
}
int max(stack<int> &stk, int deep){
    if(deep == 0){
        return INT_MIN;
    }
    int num = stk.top();
    int resMax = max(stk, deep - 1);
    stk.pop();
    int max = max(num, resMax);
    stk.push(num);
    return max;
}
int times(stack<int> &stk, int deep, int max){
    if(deep == 0){
        return 0;
    }
    int num = stk.top();
    stk.pop();
    int restTimes = times(stk, deep - 1, max);
    int times = resetTimes + (num == max ? 1 : 0);
    stk.push(num);
    return times;
}
void down(stack &stk, int deep, int max, int k){
    if(deep == 0){
        for(int i = 0; i < k; i++){
            stk.push(max);
        }
    }else{
        int num = stk.top();
        stk.pop();
        down(stk, deep - 1, max, k);
        if(num != max){
            stk.push(num);
        }
    }
}
void sortStack(stack<int> &stk) {
    int deep = deep(stk);
    int max = max(stk, deep);
    int times = times(stk, deep, max);
    down(stk, deep, max, times);
    reverse(stk);
}

汉诺塔问题

时间复杂度:$O(2^n)$

1
2
3
4
5
6
7
8
9
void f(int i, int from, int to, int other){
    if(i == 1){
        cout << "移动原盘 1 从" << from << "到" << to << endl;
    }else{
        f(i - 1, from, other, to);
        cout << "移动圆盘" << i << "从" << from << "到" << to << endl;
        f(i - 1, other, to, from);
    }
}