程序员面试金典: 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
- 程序员面试金典: 9.9 递归和动态规划 9.5求字符串的全排列
- 程序员面试金典: 9.9 递归和动态规划 9.4求某集合的所有子集
- 程序员面试金典: 9.9 递归和动态规划 9.11求布尔表达式的表达个数
- 程序员面试金典: 9.9 递归和动态规划 9.1上楼的方式
- 程序员面试金典: 9.9 递归和动态规划 9.1上楼的方式
- 程序员面试金典: 9.9 递归和动态规划 9.2机器人走路的方式
- 程序员面试金典: 9.9 递归和动态规划 9.10求堆出箱子的最大高度
- 程序员面试金典: 9.9 递归和动态规划 9.8求n分可以由25分,10分,5分,1分的硬币的表示方法
- 求字符串全排列的递归算法
- 求字符串全排列的递归算法
- 程序员面试金典: 9.9 递归和动态规划 9.9八皇后问题
- 程序员面试金典: 9.9 递归和动态规划 9.3魔术索引
- 程序员面试金典: 9.9 递归和动态规划 9.7颜色填充
- 程序员面试金典: 9.9 递归和动态规划 9.2机器人走路的方式_避免禁区
- 程序员面试金典: 9.9 递归和动态规划 9.6打印n对括号的全部有效组合
- 求字符串全排列的递归算法(java程序)
- 求字符串的全排列(递归方法)
- JAVA递归和非递归输出字符串的全排列
- spring中 context:property-placeholder 导入多个独立的配置文件
- 使用 Vue.js 制作一个简单的调查问卷平台
- 一个简单的 vue.js 实践教程
- ParameterizedType获取java泛型参数类型
- android 学习笔记9-服务 启动停止 调用服务方法 远程服务 AIDL进程通信
- 程序员面试金典: 9.9 递归和动态规划 9.5求字符串的全排列
- 黑马Java测试题错题归纳
- 【Unity】LineRenderer
- AlphaGo 超快棋遍虐人类高手(职业棋手讲解及大量网友评论)
- Caused by: java.lang.NumberFormatException: For input string: "${jdbc.initialSize}"
- 新的开始
- 不要让CPU空转
- iTerm 2 && Oh My Zsh【DIY教程——亲身体验过程】
- 206. Reverse Linked List