算法很像谜题,花费点时间精力像解谜一样的解出来,其中经历的头脑风暴,真的很有趣。
来看看这个题目:给定一组不重复的数组,输出可能的不重复的组合。
例:输入{1,2},输出 1,2 2,1
输入{1,2,3},输出
1,2,3
2,3,1
1,3,2
3,1,2
3,2,1
想想看,这个要怎么求解?
也许你会想到用暴力求解的方法,是这样的
遍历n个所有数:
遍历n-1个剩下所有数:
遍历n-2个剩下所有数:
...
没错,总有一天会算完的,大约需要n*(n-1)*(n-2)...
这是我最开始会想到的,然后呢?
{1,2} {1,2,3} {1,2,3,4}
我们发现这些输入本质上没什么不同,也许可以试试从小的找出规律
{1} 只有1种组合
{1,2} 有两种组合,跟1个数的区别是,把2加入组合中来
2 1
1 2
{1,2,3} 是将3加入到{1,2}组合中,3可以与另外两个数的相对位置有3个
3 2 1
2 3 1
2 1 3
因为{1,2}有2种不同的组合,数字3就有了2*3=6种可能性
{1,2,..., n-1,n}有多少种组合呢?
n-1个数如果有x个不重复的组合,n加入的时候就会有x*n种可能性
利用动态规划的办法,这样从较简单的实例中找出问题的规律,将微小的结果聚集在一起(记忆),最终得到答案
下面的code用c++编写
#include <iostream>
#include <vector>
using namespace std;
vector< vector< int > > premute (vector< int >& nums) {
int sizeOfNums = nums.size();
vector< vector < vector<int> > >dp(sizeOfNums);
vector<int>nums0 = {nums.at(0)};
dp[0].emplace_back(nums0);
if(sizeOfNums == 1) return dp[0];
for(int i = 1; i < sizeOfNums; i++){
int sizeOfPredp = dp[i-1].size();
for(int j = 0; j < sizeOfPredp; ++j){
int numofIter = dp[i-1][j].size();
for(int k = 0; k < numofIter + 1; ++k){
vector<int> content = dp[i-1][j];
vector<int>::iterator iter = content.begin();
content.emplace(iter + k, nums[i]);
dp[i].emplace_back(content);
}
}
}
return dp[sizeOfNums - 1];
}
int main()
{
vector< int > nums = {1,2,3,10};
vector< vector< int > > vec = premute(nums);
for(vector< vector<int>>:: iterator iter = vec.begin(); iter != vec.end(); ++iter){
vector<int> vec2 = *iter;
for(vector<int> :: iterator iter2 = vec2.begin(); iter2 != vec2.end(); ++iter2){
cout << *iter2 << " ";
}
cout << "" << endl;
}
return 0;
}