面试题28:字符串的排列
一.题目描述
输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则打印出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。
二.分析问题
1.举例分析
我们可以考虑把这个复杂的问题分解成小的问题。比如,我们把一个字符串看成由两部分组成:第一部分为它的第一个字符,第二部分是后面的所有字符。
我们求整个字符串的排列,可以看成两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。
图就是分别把第一个字符a和后面的b、c等字符交换的情形。首先固定第一个字符(如图a所示),求后面所有字符的排列。这个时候我们仍把后面的所有字符分成两部分:后面字符的第一个字符,以及这个字符之后的所有字符。然后把第一个字符逐一和它后面的字符交换(如图b所示)
注:
(a)把字符串分为两部分,一部分是字符串的第一个字符,另一部分是第一个字符以后的所有字符(有阴影背景的区域)。接下来我们求阴影部分的字符串的排列。
(b)拿第一个字符和它后面的字符逐个交换。
分析到这里,我们就可以看出,这其实是很典型的递归思路
三.代码
#include <stdio.h>
#include<string.h>
void Permutation(char* pStr);
void Permutation1(char* pStr, char* pBegin);
/*在函数Permutation1(char* pStr, char* pBegin)中,
指针pStr指向整个字符串的第一个字符,
pBegin指向当前我们做排列操作的字符串的第一个字符
。在每一次递归的时候,
我们从pBegin向后扫描每一个字符(即指针pCh指向的字符)。
在交换pBegin和pCh指向的字符之后,
我们再对pBegin后面的字符串递归地做排列操作,
直至pBegin指向字符串的末尾。*/
int main()
{
char arr[] = "abc";
Permutation(arr);
return 0;
}
void Permutation(char* pStr)
{
if (pStr == NULL)
{
return;
}
Permutation1(pStr, pStr);
}
void Permutation1(char* pStr, char* pBegin)
{
if (*pBegin == '\0')
{
printf("%s\n", pStr);
}
else
{
for (char* pCh = pBegin; *pCh != '\0'; ++pCh)
{
char temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
Permutation1(pStr, pBegin + 1);
temp = *pCh;
*pCh = *pBegin;
*pBegin = temp;
}
}
}
执行结果: