算法 全排列问题,组合问题,子集问题
子集问题
public class Solution {
public List<List<Integer>> subsets(int[] S) {
Arrays.sort(S);
List<List<Integer>> res=new ArrayList<List<Integer>>();
if(S==null||S.length<=0)return res;
List<Integer> list=new ArrayList<Integer>();
rec1(S,0,S.length-1,list,res);
return res;
}
void rec(int[] S,int s,int e,List<Integer> list,List<List<Integer>> res){
if(s==e+1){
List<Integer> temp=new ArrayList<Integer>();
temp.addAll(list);
res.add(temp);
return;
}else{
int i=s;
list.add(S[i]);
int index=list.size()-1;
rec(S,i+1,e,list,res);
list.remove(index);
rec(S,i+1,e,list,res);
}
}
void rec1(int[] S,int s,int e,List<Integer> list,List<List<Integer>> res){
if(true){
List<Integer> temp=new ArrayList<Integer>();
temp.addAll(list);
res.add(temp);
}
for(int i=s;i<=e;i++){
list.add(S[i]); int index=list.size()-1;
rec1(S,i+1,e,list,res);
list.remove(index);
}
}
}
1.子集的选择即是对元素的二选一,加入集合,不加入集合
2.注意结束条件是e+1
3.递归参数是i+1而不是s+1
组合问题:
public class Solution {
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res=new ArrayList<List<Integer>>();
if(n<=0||k<=0)return res;
List<Integer> list=new ArrayList<Integer>();
perm(k,1,n,list,res);
return res;
}
void perm(int k, int s, int e, List<Integer> list,
List<List<Integer>> res) {
if (list.size() == k) {
List<Integer> newlist = new ArrayList<Integer>();
newlist.addAll(list);
res.add(newlist);
return;
} else {
for (int i = s; i <= e; i++) {
list.add(i);
int t = list.size();
perm(k, i + 1, e, list, res);
list.remove(t - 1);
}
}
}
}
1.注意组合中的参数是i+1,其他地方与排列类似
perm(k, i + 1, e, list, res);
2.这里结束条件应该也是e+1
八皇后
- bool isOk(int *t)
- {
- int i, j;
- for (i = 1; i <= 8; i ++) {
- for (j = i + 1; j <= 8; j ++) {
- if (i - j == t[i] - t[j] || i - j == t[j] - t[i])
- return false;
- }
- }
- return true;
- }
- void getperm(int *t,int s,int e)
- {
- if(s>=e){
- if(isOk(t))
- {
- num++;
- a[num][0]=0;
- for(int i=1;i<=8;i++){
- a[num][0]=a[num][0]*10+t[i];
- a[num][i]=t[i];
- }
- v.push_back(a[num][0]);
- }
- return;
- }else{
- for(int i=s;i<=e;i++)
- {
- swap(t,s,i);
- getperm(t,s+1,e);
- swap(t,s,i);
- }
- }
- }
字符串全排列输出
void getperm(char* str,int s,int e)
{
if(s==e)
{
cout<<str<<endl;return;
}else
{
for(int i=s;i<=e;i++)
{
swap(str,s,i);
getperm(str,s+1,e);
swap(str,s,i);
}
}
}
基本模板就是这样
1.找到递归的出口,s==e,len==size-1之类,全排列不是e+1是因为,前面的排列决定好后,末位也固定了
2.递归循环实现全排列,先将s与操作值i交换,然后递归,再交换回来
3.注意这里的递归参数是s+1,区别于组合中的参数i+1
getperm(str,s+1,e);
特别的全排列:
剑指OFFER中的 题12:打印1到最大的n位数
// 这里的全排列是因为每一位都要从0到9显示一次
void func(int n)
{
char * number=new char[n+1];
number[n]='\0';
int index=0;
for(int i=0;i<10;i++)
{
number[index]='0'+i;
getrec(number,index,n);
}
delete [] number;
}
void getrec(char * number,int index,int n)
{
if(index==n-1)
{
output(number);// 从第一个不为0的字符开始显示
}else
{
for(int i=0;i<10;i++)
{
number[index+1]='0'+i;
getrec(number,index+1,n);
}
}
}
void output(char *str)
{
<span style="white-space:pre"> </span>if(str==NULL)return;
<span style="white-space:pre"> </span>while(*str=='0');
<span style="white-space:pre"> </span>cout<<*str<<endl;<span style="white-space:pre"> </span>
}