问题1:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
思路:"abcde",第一轮,a与b交换,a与c交换,a与d交换,a与e交换,
其中a每次都要回到原来的位置
第二轮,a固定,"bcde"进行上述的情形,
b与c交换,b与d交换,b与e交换,
其中b每次都要回到原来的位置
...
全部排列完毕
class Solution {
public:
vector<string> Permutation(string str) {
//可以用递归来做
vector<string> array;
if(str.size()==0)
return array;
Permutation(array, str, 0);
sort(array.begin(), array.end());
//按字典序输出各个字符串
return array;
}
void Permutation(vector<string> &array, string str, int begin)
//遍历第begin位的所有可能性
{
if(begin==str.size()-1)//最后一个字母了
array.push_back(str);
for(int i=begin; i<=str.size()-1;i++)
{
if(i!=begin && str[i]==str[begin])
//有重复字符时,跳过
continue;
swap(str[i], str[begin]);
//当i==begin时,也要遍历其后面的所有字符;
//当i!=begin时,先交换,使第begin位取到不同的可能字符,
//再遍历后面的字符
Permutation(array, str, begin+1);
//遍历其后面的所有字符;
swap(str[i], str[begin]);
//为了防止重复的情况,还需要将begin处的元素重新换回来
//举例来说“abca”,为什么使用了两次swap函数
//交换时是a与b交换,遍历;
//交换时是a与c交换,遍历;(使用一次swap时,是b与c交换)
//交换时是a与a不交换;
}
}
};
回溯法
/*
这是一个字符串排列问题,考虑使用回溯法
可以分为两部分来做
第一部分:求所有可能在第一个位置的字符,即把第一个字符与后面所有字符交换,包括自己和自己交换
第二部分:固定第一个字符,求后面所有字符的排列,即又回到第一部分
其中注意一个问题:如果第一个字符与后面某一个位置字符相同,则不用交换
*/
class Solution {
public:
vector<string> Permutation(string str) {
vector<string> all;
if(str.size() == 0){
return all;
}
string tmp;
recur(str, tmp, all, 0);
return all;
}
void recur(string str, string& tmp, vector<string> &all, int start){
if(start < 0 || str.size() == 0){
return;
}
if(str.size() == start){
all.push_back(tmp);
return;
}
for(int i = start; i < str.size(); i++){
if(i != start && str[i] == str[start]){ //如果字符相同,不用交换
continue;
}
swap(str[i], str[start]);
tmp += str[start];
recur(str, tmp, all, start + 1);
tmp.pop_back(); //回溯法的关键
}
}
};
问题2:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
//从头扫描字符串得到第一个字符,针对第一个字符,有两种选择
//把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;
//如果不把这个字符放到组合中去,则需要在剩下的n-1个字符中选取m个字符
//函数功能 : 从一个字符串中选m个元素
//函数参数 : pStr为字符串, m为选的元素个数, result为选中的
//返回值 : 无
void Combination_m(char *pStr, int m, vector<char> &result)
{
if(pStr == NULL || (*pStr == '\0'&& m != 0))
return;
if(m == 0) //递归终止条件
{
for(unsigned i = 0; i < result.size(); i++)
cout<<result[i];
cout<<endl;
return;
}
//选择这个元素
result.push_back(*pStr);
Combination_m(pStr + 1, m - 1, result);
result.pop_back();
//不选择这个元素
Combination_m(pStr + 1, m, result);
}
//函数功能 : 求一个字符串的组合
//函数参数 : pStr为字符串
//返回值 : 无
void Combination(char *pStr)
{
if(pStr == NULL || *pStr == '\0')
return;
int number = strlen(pStr);
for(int i = 1; i <= number; i++)
{
vector<char> result;
Combination_m(pStr, i, result);
}
}
/*
输入n个字符,那么形成的组合长度有1、2、... 、n
在n个字符中求长m的字符时,可以分成两部分:第一个字符和其余所有字符
如果组合中包含第一个字符,则在剩余字符中求m-1个字符
如果组合中不包含第一个字符,则在剩余字符中求m个字符
就可以用递归的方法求解
*/
class Solution
{
public:
vector<string> combination(string str){
vector<string> all;
if (str.size() == 0) {
return all;
}
string tmp;
for (int i = 1; i <= str.size(); i++) {
recur(str, tmp, 0, i, all);
}
return all;
}
void recur(string str, string &tmp, int start, int number, vector<string>& all){
if (number == 0) {
all.push_back(tmp);
return;
}
if (start == str.size()) {
return;
}
if (number > str.size() - start) {
return;
}
tmp += str[start];
recur(str, tmp, start + 1, number - 1, all);
tmp.pop_back();
recur(str, tmp, start + 1, number, all);
}
};
问题3:n皇后问题,在一个N*N的棋盘上放置N个皇后,使其不能互相攻击(同一行、同一列、同一斜线上的皇后都会自动攻击),即任意两个皇后不得处于同一行、同一列、同意斜线上。
/*
经典的N皇后问题
假如N=4
我们可以定义一个数组column[4],数组中第i个数字表示位于第i行的皇后的列号
并将0,1,2,3分别放入数组中,放入的时候判断是否在同一列以及是否时一条斜线
它们肯定不会在同一行,因为数组下标0,1,2,3各不相同,因此所在行肯定不同
*/
class Solution{
public:
int totalNQueens(int n) {
if (n < 0) {
return 0;
}
vector<int> vec(n);
int sum = 0;
QueenCore(0, n, vec, sum);
return sum;
}
void QueenCore(int index, int n, vector<int> &vec, int &sum) {
if (index >= n) {
sum++;
} else {
for (int i = 0; i < n; i++) {
vec[index] = i;
if (Diagonal(vec, index)) {
//判断是否在同一列或者是否在一条斜线上
QueenCore(index + 1, n, vec, sum);
}
}
}
}
bool Diagonal(const vector<int> &vec, int index) {
//判断是否在同一列或者是否在一条斜线上
for (int i = 0; i < index; i++) {
if ((abs(vec[i] - vec[index]) == abs(i - index)) || vec[i] == vec[index]) {
return false;
}
}
return true;
}
}
问题4:输入一个含有8个数字的数组,判断有没有可能把这8个数字分别放在正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和都相等。
/*
简而言之,这就是一个全排列问题
把这8个数全排列,之后判断正方体的三个像对面是否相等即可
*/
class Solutin{
public:
bool cubeVertex(vector<int> vec) {
if (vec.size() != 8) {
return false;
}
return cubeCore(vec, 0);
}
bool cubeCore(vector<int>& vec, int start) {
if (vec.size() != 8 || start < 0) {
return false;
}
bool result = false;
if (start == vec.size() - 1) { //判断正方体的三个相对面是否相等
if (Sum(vec, 0, 1, 2, 3) == Sum(vec, 4, 5, 6, 7)
&& Sum(vec, 0, 2, 4, 6) == Sum(vec, 1, 3, 5, 7)
&& Sum(vec, 0, 1, 4, 5) == Sum(vec, 2, 3, 6, 7)) {
result = true;
}
}
else {
for (int i = start; i < vec.size(); i++) {
if (i != start && vec[i] == vec[start]) {
continue;
}
swap(vec[i], vec[start]);
result = cubeCore(vec, start + 1);
if (result) { //一旦为true,则直接break,后面无需在做排序
break;
}
swap(vec[i], vec[start]);
}
}
return result;
}
int Sum(vector<int> vec, int i, int j, int k, int l) {
return vec[i] + vec[j] + vec[k] + vec[l];
}
}
参考博客:
https://blog.csdn.net/wuzhekai1985/article/details/6643127#commentBox