程序员面试金典: 9.9 递归和动态规划 9.5求字符串的全排列

来源:互联网 发布:淘宝考试答案50题2016 编辑:程序博客网 时间:2024/06/06 05:48
#include <iostream>#include <stdio.h>#include <string>#include <vector>#include <set>using namespace std;/*问题:编写一个方法,确定某字符串的所有排列组合。分析:字符串排列组合的生成可以用递归来做。      比如给定字符串abc,  在刘汝佳算法竞赛中有这个题目:他是采用摆放的方法来做,比如先尝试所有可能成为第一个字符的s,对每一个符合要求的  字符串进行递归处理,递归处理完要回溯,会重新将之前摆放位置清空。  当摆放的字符串长度满足字符串原始长度后,就输出结果,并返回输入:aaaabaabcaab输出:aaaaba aab baaabc acb bac bca cab cbaaab aba baa关键:1 他是采用摆放的方法来做,比如先尝试所有可能成为第一个字符的s,对每一个符合要求的  字符串进行递归处理,递归处理完要回溯,会重新将之前摆放位置清空。  当摆放的字符串长度满足字符串原始长度后,就输出结果,并返回2for(int i = 0 ; i < size ; i++){        if( i == 0 || str[i] != str[i-1] ){//如果当前字符串是可以放入的,放入之后应该递归摆放下一个if(isOk(str , i , strResult , index)){strResult[index] = str[i];++index;getStringPermutation(str, results , index , strResult);//回溯,以便用于再次生成全排列--index; }}需要做判断重复处理,比如aaa这种,当前元素str[i]和str[i-1]不能重复,经典:首先明确: 在for循环下面str[i] 和 str[i-1]都是针对位置strResult[index]上的元素做摆放尝试的假如1】str[i-1]曾经作为strResult[index],如果1.1】 str[i]也可以作为strResult[index],                                如果1.1.1】str[i] != str[i-1],显然不会涉及到重复摆放问题如果1.1.2】str[i] = str[i-1],strResult[index]被两个相同的字符都重复摆放,所以下面的条件                    if( i == 0 || str[i] != str[i-1] ) 可以确保不会发生这种情况    如果1.2】str[i]不能作为strResult[index],不存在重复摆放问题假如2】str[i-1]没有作为strResult[index],如果2.1】 str[i]也可以作为strResult[index],                                如果2.1.1】str[i] != str[i-1],显然不会涉及到重复摆放问题如果2.1.2】str[i] = str[i-1],strResult[index],str[i-1]必定也能作为strResult[index],与2】悖论,    该分支不可能发生    如果1.2】str[i]不能作为strResult[index],不存在重复摆放问题分析了上述情况,得出:分支2中所有情况不涉及重复摆放问题,分支1中只有str[i-1]曾经作为strResult[index],且str[i] = str[i-1]时可以规避重复摆放问题3为了防止提供的字符串为aba这种,即存在重复字符串,但不在一起,我们可以把最终的结果存放在set中,来过滤重复的*/const int MAXSIZE = 256;const int CHAR_MAXSIZE = 10000;//判断字符str[index]是否可以作为全排列结果字符串中strResult[index]对应字符bool isOk(string& str , int k , char* strResult , int index){if(str.empty()){return false;}int hashOriginArr[MAXSIZE];memset(hashOriginArr , 0 , sizeof(hashOriginArr));int size = str.size();//统计原始字符串中每个字符出现次数for(int i = 0 ; i < size ; i++){int ch = (int)str.at(i);hashOriginArr[ch]++;}int hashResultArr[MAXSIZE];memset(hashResultArr , 0 , sizeof(hashResultArr));//统计待生成全排列字符串中每个字符出现次数for(int i = 0 ; i < index ; i++){int ch = (int)strResult[i];hashResultArr[ch]++;}//判断待放入位置字符 加上1 后是否小于等于 原始字符串中该字符出现次数int ch = (int)str.at(k);if( hashResultArr[ch] + 1 <= hashOriginArr[ch] ){return true;}else{return false;}}void getStringPermutation(string& str, vector<string>& results , int& index , char* strResult){if(str.empty() || index < 0){return;}//如果当前已经生成结果,直接输出if(index == str.size()){strResult[index] = '\0';string result(strResult);results.push_back(result);}//如果,当前字符串的全排列还没有生成,下面先生成字符串在index位置应该摆放的字符else{int size = str.size();for(int i = 0 ; i < size ; i++){/*需要做判断重复处理,比如aaa这种,当前元素str[i]和str[i-1]不能重复,经典:首先明确: 在for循环下面str[i] 和 str[i-1]都是针对位置strResult[index]上的元素做摆放尝试的假如1】str[i-1]曾经作为strResult[index],如果1.1】 str[i]也可以作为strResult[index],                                        如果1.1.1】str[i] != str[i-1],显然不会涉及到重复摆放问题    如果1.1.2】str[i] = str[i-1],strResult[index]被两个相同的字符都重复摆放,所以下面的条件                          if( i == 0 || str[i] != str[i-1] ) 可以确保不会发生这种情况          如果1.2】str[i]不能作为strResult[index],不存在重复摆放问题假如2】str[i-1]没有作为strResult[index],如果2.1】 str[i]也可以作为strResult[index],                                        如果2.1.1】str[i] != str[i-1],显然不会涉及到重复摆放问题    如果2.1.2】str[i] = str[i-1],strResult[index],str[i-1]必定也能作为strResult[index],与2】悖论,           该分支不可能发生          如果1.2】str[i]不能作为strResult[index],不存在重复摆放问题分析了上述情况,得出:分支2中所有情况不涉及重复摆放问题,  分支1中只有str[i-1]曾经作为strResult[index],且str[i] = str[i-1]时可以规避重复摆放问题*/if( i == 0 || str[i] != str[i-1] ){//如果当前字符串是可以放入的,放入之后应该递归摆放下一个if(isOk(str , i , strResult , index)){strResult[index] = str[i];++index;getStringPermutation(str, results , index , strResult);//回溯,以便用于再次生成全排列--index;strResult[index] = '\0';}}}}}void printResult(vector<string>& results){if(results.empty()){cout << "Error!" << endl;return;}//为了防止results中有相同字符串,用setint size = results.size();set<string> setString;for(int i = 0 ; i < size ; i++){setString.insert(results[i]);}int i = 0;for(set<string>::iterator it = setString.begin() ; it != setString.end() ; it++){if( 0 != i){cout << "," << *it ; }else{cout << *it;}i++;}/*for(int i = 0 ; i < size ; i++){if( 0 != i){cout << "," << results[i] ; }else{cout << results[i];}}*/cout << endl;}void process(){string str;vector<string> results;int index = 0;while(cin >> str){results.clear();index = 0;char strResult[CHAR_MAXSIZE];getStringPermutation(str, results , index , strResult);printResult(results);}}int main(int argc , char* argv[]){process();getchar();return 0;}

0 0
原创粉丝点击