字符串的全排列

点:理解全排列,递归的运用


题意:如字符串abcd,获取其全排列就是:abcd、abdc、acbd、acdb、adcb、adbc、

     bacd、badc、bcad、bcda、bdca、bdac、

     cbad、cbda、cabd、cadb、cdba、cdab、

     dbca、dbac、dcba、dcab、dacb、dabc

共24种

剑指offer面试题28


思路:全排列是一个较常见的题,表面感觉不特别难以理解,但实际做到真正理解和运用还是比较困难的:

简单直观的想,abc的全排列,abc、acb、bac、bca、cab、cba,就是字母a加上字母bc的两个组合bc和cb,字母b加上ac的组合ac和ca,字母c加上ab的组合ab和ba

这就是:从简单例子分析出规律,这点在面试时非常重要,因为很多使用动态归划、递归、以及一些需要洞察出其规律的题都是这样,必须要洞察到规律,然后才能选择正确的道路继而写的正确,如何洞察规律?就必须从简单的例子中分析出;

如这个全排列,由上面的简单例子的结果"字母a加上字母bc的两个组合bc和cb,字母b加上ac的组合ac和ca,字母c加上ab的组合ab和ba",发现一种规律是:

依次以字符串的每个字母为前缀,加上其余字母的排列组合,就是全排列。

而后面每个字母的排列组合,也同样是一个全排列问题。


再具体的看,abc,首先a做前缀,然后是获取bc的全排列,包括bc和cb,然后b做全排列。。。然后c做全排列;

大致一个算法的规律是:每个字母做前缀,然后后面的子串也递归的这样去干,直到当前字符串结束为止,然后递归回来继续,比如abc,

1、a做前缀去找bc的全排列

1.1、b做前缀找c的全排列,就是c,输出一个abc

1.2、b和c交换,c做前缀找b的全排列,就是b,输出一个acb


2、b做前缀找ac的全排列

.............

3、c做前缀找ab的全排列

.............


如果是更复杂的abcd呢?对于上面的第1步,a做前缀找bcd的全排列,bcd的全排列的找法和abc的找法是一样的。

至此基本明确了找的大致思路,并且很适应于递归,递归的停止条件是什么?就是上面的第1步的b和c交换后,发现没有可交换的余地了。那么递归不断入栈的参数是?是当前准备要和其后面字符串的字符们不断交换的字符的位置,想象abcde的交换过程,假设在b和c交换后是acbde,位置是b的索引是2,接下来马上就是b还要和b、d、e交换,这3个交换的递归过程,分别需要位置参数2、3、4。到e再递归时,也就是索引为4时再继续递归时,就到了递归停止条件了,这时候设计为输出当前字符串的时候。

代码很老套,关键还是理解思路。

全排列也是很多其他面试题的至少结果正确的解法。


每个字符串全排列有多少种情况?一个字符是一种,两个字符是2个 *1 = 2种,3个字符是3个 * f(2) = 6种,4个字符是4个 * f(3) = 24种,也就是1*2*3*......N种,N是字符串长度


代码:

#include <iostream>

void swap (std::string &str, int i, int j) {
    if (i == j) {
        return;
    }
    char t = str[i];
    str[i] = str[j];
    str[j] = t;
}

void perm (std::string &raw, int idx, const int size) {
    if (idx == size) {
        std::cout << raw << "\t";
    } else {
        for (int i = idx; i < size; i++) {
            swap(raw, i, idx);
            perm(raw, idx + 1, size);
            swap(raw, i, idx);
        }
    }
}

int main () {
    std::string raw = "abcde";
    perm(raw, 0, raw.length());
    std::cout << std::endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值