字符的全排列
题目描述
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思路:DFS
代码:
class Solution {
public:
void allpermute(vector<int>&nums,vector<int>temp,vector<vector<int>> &results)
{
if(temp.size()==nums.size())
{
results.push_back(temp);
}
for(int i=0;i<nums.size();i++)
{
auto iter=find(temp.begin(),temp.end(),nums[i]);
if(iter!=temp.end())
{
continue;
}
temp.push_back(nums[i]);
allpermute(nums,temp,results);
temp.pop_back();
}
return;
}
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> results ;
int len = nums.size();
vector<int>temp;
allpermute(nums,temp,results);
return results;
}
};
字符的组合
题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。
上面我们详细讨论了如何用递归的思路求字符串的排列。同样,本题也可以用递归的思路来求字符串的组合。
思路:同样是用递归求解。可以考虑求长度为n的字符串中m个字符的组合,设为C(n,m)。原问题的解即为C(n, 1), C(n, 2),...C(n, n)的总和。对于求C(n, m),从第一个字符开始扫描,每个字符有两种情况,要么被选中,要么不被选中,如果被选中,递归求解C(n-1, m-1)。如果未被选中,递归求解C(n-1, m)。不管哪种方式,n的值都会减少,递归的终止条件n=0或m=0。
//函数功能 : 从一个字符串中选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);
}
}
字符的子集
描述
给定一个含不同整数的集合,返回其所有的子集
子集中的元素排列必须是非降序的,解集必须不包含重复的子集
您在真实的面试中是否遇到过这个题? 是
样例
如果 S = [1,2,3]
,有如下的解:
-
[
-
[3],
-
[1],
-
[2],
-
[1,2,3],
-
[1,3],
-
[2,3],
-
[1,2],
-
[]
-
]
挑战
你可以同时用递归与非递归的方式解决么?
递归的方法:
不要去想递归是如何一层一层调用的,而是要想如果解决当前问题,找到递归的出口
和字符串的排列一样,将数组分为第一个元素和后面的所有的元素,此时面临取第一个元素,递归剩余的元素或者不取第一个元素(即直接递归剩余元素)
代码如下:
class Solution {
public:
/**
* @param nums: A set of numbers
* @return: A list of lists
*/
vector<vector<int>> subsets(vector<int> &nums) {
// write your code here
//这里排序并不必须,只是为了子集中元素以递增排序
sort(nums.begin(), nums.end());
vector<vector<int>> subs;
vector<int> sub;
genSubsets(nums, 0, sub, subs);
return subs;
}
void genSubsets(vector<int>& nums, int start, vector<int>& sub, vector<vector<int>>& subs) {
//我们发现这里好像并没有递归出口,因为终止条件由下面for循环控制
subs.push_back(sub);
for (int i = start; i < nums.size(); i++) {
//情况一:子集包含元素nums[i]
sub.push_back(nums[i]);
//为何是i+1,因为已经解决了第i个元素,需要递归从第i+1个元素开始求解
genSubsets(nums, i + 1, sub, subs);
//情况二:子集不包含nums[i],即略过第i个元素
//可以想象,不去管上一条递归语句,当下一次循环到i+1时,第i个元素已经略过
sub.pop_back();
}
}
};
题目:输入两个整数n和m,从数列1,2,3...n中随意取几个数,使其和等于m,要求列出所有的组合。
#include <iostream>
#include <list>
using namespace std;
list<int> list1;
void find_factor(int sum,int n)
{
//递归出口
if(n<=0||sum<=0)
return;
//输出找到的数
if(sum==n)
{
list1.reverse();
for(list<int>::iterator iter=list1.begin();iter!=list1.end();iter++)
cout<<*iter<<"+";
cout<<n<<endl;
list1.reverse();
}
list1.push_front(n);
find_factor(sum-n,n-1);//n放在里面
list1.pop_front();
find_factor(sum,n-1);//n不放在里面
}
int main(void)
{
int sum,n;
cin>>sum>>n;
cout<<"所有可能的序列,如下:"<<endl;
find_factor(sum,n);
return 0;
}