剑指Offer----面试题28:字符串的排列 & 去重
来源:互联网 发布:一个程序员的奋斗史txt 编辑:程序博客网 时间:2024/05/16 07:33
题目:
输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印输出字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab、cba。
分析:
首先求得所有可能出现在第一个位置上的字符,即把第一个字符和后边所有的字符交换;
固定第一个字符,求后面所有字符的排列。
如abc:
第一步:将第一行数据分别和第二行和第三行数据交换
abcbaccab
第二步:保持第一列不变,将第二行数据分别和第三行数据交换
第二步:保持第一列不变,将第二行数据分别和第三行数据交换
acbbcacba
交换完毕,显然,要用到递归的知识。
方法一:
源代码如下:
#include<iostream>using std::endl;using std::cout;void Permutation(char *str);void Permutation(char *str, char *begin);void Permutation(char *str){if (str == NULL){cout << "Thr array is empty" << endl;return;}cout << str << "的排列为:";Permutation(str, str);}void Permutation(char *str, char *begin){if (*begin == '\0')cout << str << " ";else{for (char *pCh = begin; *pCh != '\0'; ++pCh){//交换第一个字符和当前所指向的字符char temp = *pCh;*pCh = *begin;*begin = temp;Permutation(str, begin + 1);//变回原来的形式temp = *pCh;*pCh = *begin;*begin = temp;}}}void test11(){cout << "\t=======测试空指针========" << endl;Permutation(NULL);}void test12(){cout << "\t=======测试只有分隔符的指针========" << endl;char ch[] = "";Permutation(ch);}void test13(){cout << "\t=======测试只有一个元素的指针========" << endl;char ch[] = "a";Permutation(ch);}void test14(){cout << "\t=======测试只有多个元素的指针========" << endl;char ch[] = "abc";Permutation(ch);}void test15(){cout << "\t=======测试只有多个元素的指针========" << endl;char ch[] = "abcd";Permutation(ch);}int main(){test11();cout << endl;test12();cout << endl;test13();cout << endl;test14();cout << endl;test15();cout << endl;system("pause");return 0;}
运行结果:
=======测试空指针========Thr array is empty =======测试只有分隔符的指针========的排列为: =======测试只有一个元素的指针========a的排列为:a =======测试只有多个元素的指针========abc的排列为:abc acb bac bca cba cab =======测试只有多个元素的指针========abcd的排列为:abcd abdc acbd acdb adcb adbc bacd badc bcad bcda bdcabdac cbad cbda cabd cadb cdab cdba dbca dbac dcba dcab dacb dabc请按任意键继续. . .
方法二:
原理和方法一相同,但是代码的实现方式略有不同。
源代码如下:
#include<iostream>#include<cstdlib>#include<cstdio>using std::cout;using std::endl;int num = 1; //局部静态变量,用来统计全排列的个数 //k表示当前选取到第几个数,m表示公有多少个数void Permutation3(char *pStr, int k, int m){if ((pStr == NULL) || (m == 0))return;if (k == m){printf("第%d个排列\t%s\n", num++, pStr);}else{for (int i = k; i < m; i++){std::swap(*(pStr + k), *(pStr + i));Permutation3(pStr, k + 1, m);std::swap(*(pStr + k), *(pStr + i));}}}void test1111(){cout << "\t=======测试空指针========" << endl;Permutation3(NULL, 0, 0);}void test1222(){cout << "\t=======测试只有分隔符的指针========" << endl;char ch[] = "";Permutation3(ch, 0, 0);}void test1333(){cout << "\t=======测试只有一个元素的指针========" << endl;char ch[] = "a";Permutation3(ch, 0, 1);}void test1444(){cout << "\t=======测试只有多个元素的指针========" << endl;char ch[] = "abc";Permutation3(ch, 0, 3);}void test1555(){cout << "\t=======测试只有多个元素的指针========" << endl;char ch[] = "abcd";Permutation3(ch, 0, 4);}int main(){test1111();cout << endl;num = 1;test1222();cout << endl;num = 1;test1333();cout << endl;num = 1;test1444();cout << endl;num = 1;test1555();cout << endl;num = 1;system("pause");return 0;}
运行结果如下:
=======测试空指针======== =======测试只有分隔符的指针======== =======测试只有一个元素的指针========第1个排列 a =======测试只有多个元素的指针========第1个排列 abc第2个排列 acb第3个排列 bac第4个排列 bca第5个排列 cba第6个排列 cab =======测试只有多个元素的指针========第1个排列 abcd第2个排列 abdc第3个排列 acbd第4个排列 acdb第5个排列 adcb第6个排列 adbc第7个排列 bacd第8个排列 badc第9个排列 bcad第10个排列 bcda第11个排列 bdca第12个排列 bdac第13个排列 cbad第14个排列 cbda第15个排列 cabd第16个排列 cadb第17个排列 cdab第18个排列 cdba第19个排列 dbca第20个排列 dbac第21个排列 dcba第22个排列 dcab第23个排列 dacb第24个排列 dabc请按任意键继续. . .
考虑去重问题:
由于全排列就是从第一个数字起每个数分别与它后面的数字交换。我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这二个数就不交换了。如122,第一个数与后面交换得212、221。然后122中第二数就不用与第三个数交换了,但对212,它第二个数与第三个数是不相同的,交换之后得到221。与由122中第一个数与第三个数交换所得的221重复了。所以这个方法不行。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
换种思维,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到解决221。此时全排列生成完毕。
这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。
源代码:
#include<iostream>using namespace std;#include<assert.h>//在[nBegin,nEnd)区间中是否有字符与下标为pEnd的字符相等bool IsSwap(char* pBegin, char* pEnd){char *p;for (p = pBegin; p < pEnd; p++){if (*p == *pEnd)return false;}return true;}void Permutation4(char* pStr, char *pBegin){assert(pStr);if (*pBegin == '\0'){static int num = 1; //局部静态变量,用来统计全排列的个数printf("第%d个排列\t%s\n", num++, pStr);}else{for (char *pCh = pBegin; *pCh != '\0'; pCh++) //第pBegin个数分别与它后面的数字交换就能得到新的排列 {if (IsSwap(pBegin, pCh)){swap(*pBegin, *pCh);Permutation4(pStr, pBegin + 1);swap(*pBegin, *pCh);}}}}int main(void){char str[] = "abab";Permutation4(str, str);system("pause");return 0;}
运行结果如下:
第1个排列 abab第2个排列 abba第3个排列 aabb第4个排列 baab第5个排列 baba第6个排列 bbaa请按任意键继续. . .
0 0
- 剑指Offer----面试题28:字符串的排列 & 去重
- 剑指offer - 面试题28:字符串的排列(递归+去重)
- 剑指offer面试题 字符串的排列
- 剑指offer面试题28字符串的所有排列permutation
- [剑指offer][面试题28]字符串的排列
- 【剑指offer】面试题28:字符串的排列
- 剑指Offer:面试题28 字符串的排列
- 剑指offer 面试题28—字符串的排列
- 《剑指Offer》面试题28:字符串的排列
- 《剑指Offer》学习笔记--面试题28:字符串的排列
- 剑指offer--面试题28:字符串的排列--Java实现
- 剑指offer--面试题28:字符串的排列--Java实现
- 【剑指Offer学习】【面试题28 :字符串的排列】
- 剑指offer面试题28-字符串的排列
- 剑指offer-面试题28:字符串的排列
- 剑指offer 面试题28:字符串的排列
- 剑指offer之面试题28:字符串的排列
- 剑指offer之面试题28字符串的排列
- 手机开发实战88——WAP介绍1
- Allowed memory size of 134217728 bytes exhausted
- Unity Shader简单Shader一
- 手机开发实战89——WAP介绍2
- linux下的sqlite入门
- 剑指Offer----面试题28:字符串的排列 & 去重
- JavaPoet源码初探
- 装修计划
- Maximum Depth of Binary Tree
- 如何应对失眠
- C#之四十六 迷你贪吃蛇项目
- 温故而知新(一)
- 最短路径 k
- WebService之HelloWorld(服务器端)