动态规划题目:找出不重复的组合

1,074 阅读2分钟
算法很像谜题,花费点时间精力像解谜一样的解出来,其中经历的头脑风暴,真的很有趣。

来看看这个题目:给定一组不重复的数组,输出可能的不重复的组合。

例:输入{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;
}