全排列,组合问题

包括了排列,组合,子集问题,子集带重复问题,基本全了,就差在看看leetcode以前怎么写的了

  1 //全排列的两种方法
  2 #include <iostream>
  3 #include <vector>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 //方法一,采用swap方法
  8 void quanpailie(char * A,int first,int n)
  9 {
 10     if(A==NULL)
 11     {
 12         cout<<"A is NULL"<<endl;
 13         return;
 14     }
 15     if(n<=1)
 16     {
 17         cout<<A<<endl;
 18         return;
 19     }
 20     for(int i=first;i<first+n;i++)
 21     {
 22         swap(A[i],A[first]);
 23         quanpailie(A,first+1,n-1);
 24         swap(A[i],A[first]);
 25     }
 26     return;
 27 }
 28 
 29 //采用字典序全排序,就是采用的字典排序思想,从后向前找出第一个A[i]<A[i+1],如果没有就说明结束,
 30 //然后在从右向左找出第一个大于A[i]的,进行交换,然后逆序i+1到最后(也就是逆序j到最后)。
 31 void quanpailie2(char * A,int n)
 32 {
 33     cout<<A<<endl;              //输出最开始的“abc”
 34     if(A==NULL||n<=0)
 35         return;
 36     while(true)
 37     {
 38         int i;
 39         for(i=n-2;i>=0;i--)
 40         {
 41             if(A[i]<A[i+1])
 42                 break;
 43         }
 44         if(i<0)
 45         {
 46             break;
 47         }
 48         for(int k=n-1;k>=0;k--)
 49         {
 50             if(A[k]>A[i])
 51             {
 52                 swap(A[i],A[k]);
 53                 break;
 54             }
 55         }
 56         reverse(A+i+1,A+n);
 57         cout<<A<<endl;
 58     }
 59 }
 60 
 61 /*
 62 子集问题,子集问题有两种情况,比如正常的{1,2,3}求子集就是{},{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}
 63 还有就是有重复的情况比如{1,2,2}求子集就是{},{1},{2},{1,2},{2,2},{1,2,2}
 64 注意区分子集问题和组合问题,组合问题为最简单的递归回溯问题1,2,3,4,选2个为{1,2},{1,3},{1,4},{2,3},{2,4},{3,4},{3,4}
 65 */
 66 
 67 //组合问题(子集问题),方法一,采用vector,比较取巧,完全不计较空间的解法了,这个是全组合问题给你abc返回
 68 //{},{a},{b},{c},{a,b},{a,c},{b,c},{a,b,c},注意和C(n,k)的区别
 69 //最简单情况,没有重复的方法一,{1,2,3}
 70 void subsets(char *A ,int n,vector<vector<char>> &result)
 71 {
 72     vector<char> tmp;                            //空vector
 73         result.push_back(tmp);
 74     for(int i=0;i<n;i++)
 75     {
 76         int size=result.size();                //注意,必须提前村上size,不然每次result.size()都是新的
 77         for(int j=0;j<size;j++)
 78         {
 79             vector<char> t=result[j];         //必须用个临时的新的,否则会更改result[j]的值。
 80             t.push_back(A[i]);                //注意是push_back(A[i])
 81             result.push_back(t);
 82         }
 83     }
 84     //最后result里面有一个空的
 85     //result.erase(result.begin());  //或者不删除也行,在显示的时候也可以不显示,但会多打出一个换行符
 86     /*for(int i=0;i<result.size();i++)
 87     {
 88         for(int j=0;j<result[i].size();j++)
 89         {
 90             cout<<result[i][j];
 91         }
 92         cout<<endl;
 93     }*/
 94 }
 95 
 96 //子集问题,方法二,采用递归方法,也是普通的{1,2,3,4}
 97 void subsets2(char *A,int n,int first,vector<vector<char>> &result,vector<char> &tmp)
 98 {
 99     result.push_back(tmp);
100     for(int i=first;i<n;i++)
101     {
102         tmp.push_back(A[i]);
103         subsets2(A,n,i+1,result,tmp);
104         tmp.pop_back();
105     }
106 
107 }
108 
109 
110 //子集问题,特殊的情况处理如{1,2,2}这种情况的子集,方法一,也是迭代方法,只不过加了去重的思想
111 
112 void subsets_without_repeat(char *A ,int n,vector<vector<char>> &result)
113 {
114     sort(A,A+n);//注意必须先排序
115     vector<char>tmp;
116     result.push_back(tmp);
117     int size,pre_size,j;
118     for(int i=0;i<n;i++)
119     {
120         size=result.size();
121         if(i-1>=0&&A[i]==A[i-1])             //如果重复了,就让j是从上次的size开始,注意初始判断i-1>=0
122             j=pre_size;
123         else
124             j=0;
125         while(j<size)
126         {
127             vector<char> t=result[j];
128             t.push_back(A[i]);
129             result.push_back(t);
130             j++;
131         }
132         pre_size=size;                    //记录上次的size
133     }
134 }
135 
136 /*子集问题,特殊的情况处理如{1,2,2}这种情况的子集,方法二,也是采用递归方法,只不过加了去重的思想,去重的思路是{1,2,2},
137 当是{},{1},{1,2},{1,2,2},tmp原来是{1,2},然后弹出2,tmp是{1},下一个元素是第二个2时,这个就可以跳过了,不用再有{1,2}了,然后1弹出
138 2入为{2},即i!=first&&A[i]==A[i-1]就可以跳过了
139 */
140 void  subsets_without_repeat2(char *A,int n ,int first,vector<vector<char>> & result,vector<char> & tmp)
141 {
142     result.push_back(tmp);
143     for(int i=first;i<n;i++)
144     {
145         if(i!=first&&i-1>=0&&A[i]==A[i-1])
146             continue;
147         tmp.push_back(A[i]);
148         subsets_without_repeat2(A,n,i+1,result,tmp);
149         tmp.pop_back();
150     }
151 }
152 
153 
154 /*
155 组合问题,C(n,k)问题,很容易,用递归回溯的典型,1,2,3,4 ,给定n为4,k=2,则{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}
156 */
157 void compose(char *A,int n,int start,int dep,vector<vector<char>> &result,vector<char> &tmp)
158 {
159     if(A==NULL||n<=0)
160         return;
161     if(dep==2)
162     {
163         result.push_back(tmp);
164         return;
165     }
166     for(int i=start;i<n;i++)
167     {
168         tmp.push_back(A[i]);
169         compose(A,n,i+1,dep+1,result,tmp);
170         tmp.pop_back();
171     }
172 }
173 
174 int main()
175 {
176     char A[]="1234";
177     vector<vector<char>> result;
178     vector<char> tmp;
179     //quanpailie(A,0,4);
180     //quanpailie2(A,4);
181     //subsets(A,3,result);
182     //subsets2(A,4,0,result,tmp);
183     //subsets_without_repeat(A,3,result);
184     //subsets_without_repeat2(A,3,0,result,tmp);
185     compose(A,4,0,0,result,tmp);
186     for(int i=0;i<result.size();i++)
187     {
188         for(int j=0;j<result[i].size();j++)
189         {
190             cout<<result[i][j];
191         }
192         cout<<endl;
193     }
194     system("pause");
195 }

转载于:https://www.cnblogs.com/zmlctt/p/3848115.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值