排列和组合简单的递归思路以及C++实现

9 篇文章 0 订阅

本文将讲解如何通过递归的方法实现全排列和组合,会详细讲解递归的思路,最后还会给出c++实现的源码。先前学习数据结构和算法的时候一直没有弄明白它们的递归思路,今日遇到,细一思考,发现并没有之前那么难,于是把码下来,同时记下思路。

排列

先讲排列:比如A B C D 四个字母的全排列就是下面24种

ABCD, ABDC, ACDB, ACBD, ADBC, ADCB, BCDA, BCAD, BDAC, BDCA, BACD, BADC, CDAB, CDBA, CABD, CADB, CBDA, CBAD, DABC, DACB, DBCA, DBAC, DCAB, DCBA

假设所有需要排列的字母有n个( R1,R2...Rn ),如果后面(n-1)个字母已经是全排列的了( Rm 表示后面n-1个字母),那么 (R0,Rm),(R1,Rm)...(Rn,Rm) 就是全排列的,其中 Ri 不在 Rm 中。也就是,先把后面n-1个字母全排列好,再全排列所有n个,如何排列n个呢? 让所有的字母轮流排在第一个的位置一次。这样下去,在全排列好后面n-1个之前,先全排列好后面n-2个、、、直到第n个。这也就是递归思路。

#include <vector>
#include <iostream>

using namespace std;

/*
全排列
*/
class TotalOrdering {
    //需要排列的字母
    vector<char> letters = { 'A', 'B', 'C', 'D' };
    vector<string> result;//保存结果

public:

    /*
    参数:
    start表示需要排列字母中开始的下标,开始的时候为0, 所以,开始的时候需要全排列的字母下标是(0, letters.size()-1)
    str表示结果字符串
    */
    void order(int start, string str) {
        if (start >= letters.size()) {//到达组后一个字母,递归结束
            result.push_back(str);
            return;
        }

        for (int i = start; i < letters.size(); ++i) {//让所有的字母放在第一个位置一次
            order(start + 1, str + letters[start]);
            forward(letters, start);
        }
    }

    //把第一个字符放置到最后的位置,其他字符往前移动一位
    //比如开始是abcd, 通过该函数之后变成bcda
    void forward(vector<char> &letters, int start) {
        if (start >= letters.size() - 1)return;

        char first = letters[start];
        int i = start + 1;
        for (; i < letters.size(); ++i) {
            letters[i - 1] = letters[i];
        }
        letters[i - 1] = first;
    }

    void print() {
        auto begin = result.begin();
        for (; begin != result.end(); ++begin) {
            string tempStr = *begin;

            cout << tempStr.c_str() << ", ";
        }
    }
};

int main() {
    TotalOrdering totalOrdering;
    totalOrdering.order(0, "");
    totalOrdering.print();

    system("pause");
    return 0;
}

组合

现在有三个集合{A, B}, {C, D}, {E, F}, 那么三个集合所有元素的组合便是ACE, ACF, ADE, ADF, BCE, BCF, BDE, BDF这八种。如果后面两个集合中的所有元素已经组合完成(这些组合记为R),同时记Ri表示第一个集合中的元素,那么{Ri, R}(其中i属于(1…n))便是所有的组合。也就是{(R1, R), (R2, R)…(R3, R)}是所有的组合。这便是递归思路。根据它实现码出下面代码:

#include <string>
#include <sstream>
#include <queue>

using namespace std;

class Solution0017 {
public:
    const string keyboard[10] = { "0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };

    //使用递归的方法
    vector<string> result;
    vector<string> letterCombinations(string digits) {
        if (digits == "") return vector<string>();

        combine(0, digits, "");
        return result;
    }

    void combine(int size, string & digits, string str) {
        if (size >= digits.length()) {
            result.push_back(str);
            return;
        }
        string letters = keyboard[digits[size] - '0'];
        for (int i = 0; i < letters.length(); ++i) {
        //把第一个集合中的元素分别和其他组合结合, 其他组合已经是“组合”
            combine(size + 1, digits, str + letters[i]);
        }
    }


};


int main() {

    Solution0017 solution;
    //第一个集合为{a,b,c}, 第二个集合为{d,e,f}
    vector<string> result = solution.letterCombinations("23");
    cout << result.size() << endl;

    system("pause");
    return 0;
}

这个例子也是leetcode中第17算法题的答案。

欢迎指教!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值