回溯法——列举多维向量

来源:互联网 发布:与阿里云合作 编辑:程序博客网 时间:2024/05/22 13:31

1.回溯法概述

   对于单维或者低维向量进行搜索时,可以非常简单的使用循环来遍历。但是随着维度的增加要怎么进行遍历呢?没错,使用回溯法可以对多维向量进行exhaustive searching。

   它的通用编程模式:

backtrack( [v1,...,vn] )      {        if ( [v1,...,vn] is well-generated )        {            if ( [v1,...,vn] is a solution ) process solution;            return;        }             for ( x = possible values of vn+1 )            backtrack( [v1,...,vn, x] );    }         call backtrack( [] );   

2.回溯法经典例题

  1>列举数组(可以重复)

    

void backtrack1(vector< vector<int> > &res,vector<int> temp,int n){    if(n==0)    {        res.push_back(temp);        return ;    }    else    {            int i;            for(i=1;i<4;i++)            {                temp.push_back(i);                backtrack1(res,temp,n-1);                temp.pop_back();            }    }}int  main(){    vector< vector<int> > res;    vector<int> temp;    backtrack1(res,temp,3);    int i,j;    for(i=0;i<res.size();i++)    {        for(j=0;j<res[i].size();j++)        {            cout<<res[i][j]<<"  ";        }        cout<<endl;    }  return 0;}
列举简图:

2> 列出[1,2,3] 的所有全排列,排列中不能有重复,只可能是1,2,3;1,3,2;2,3,1;2,1,3;3,1,2;3,2,1;共6中情况。

int used[4]={0};void backtrack(vector< vector<int> > &res,vector<int> temp,int n){    if(n==0)    {        res.push_back(temp);        return ;    }    else    {            int i;            for(i=1;i<4;i++)            {                if(!used[i])                {                    used[i]=1;                    temp.push_back(i);                    backtrack(res,temp,n-1);                    temp.pop_back();                    used[i]=0;                }            }    }}
main函数是一样的,只需要该函数名称。

3>要求输出所有的1...n之间的k个数。

   比如:n=4,k=2;输出:

[  [2,4],  [3,4],  [2,3],  [1,2],  [1,3],  [1,4],]
class Solution {public:    vector<vector<int>> combine(int n, int k) {        vector<int>temp;        com(n,k,temp,0);        return res;    }    void com(int n,int k,vector<int> temp, int m)    {        if(k==0)        {            res.push_back(temp);            return ;        }        else        {            for(int i=1;i<=n;i++)            {                if(i>m)                {                    temp.push_back(i);                    com(n,k-1,temp,i);                    temp.pop_back();                }            }        }    }private:    vector<vector<int>> res;};
4>输出序列中所有和为固定值的子序列:

  例如:序列2,3,6,7 和为7,那么输出

                                                 [7]
                                                 [2, 2, 3]

class Solution {  private:      const int index_count;      vector<vector<int> > results;  public:      Solution() : index_count(10000) {};      // index记录当前找到的候选数字,n表示当前正在找第几个,n是index的下标不是candidates的下标      void backtrace(int target, int sum, vector<int> &candidates, int index[], int n)      {          if (sum > target)          {              return; // 回溯          }          if (sum == target)          {              vector<int> result;              for (int i = 1; i <= n; ++i)              {                  result.push_back(candidates[index[i]]);               }              results.push_back(result);              return; // 此处可以不加,如果不加return由于都是正整数,到下面的计算时会多进行一次无用的递归。          }            // 深度搜索,为了避免重复,每次从当前候选项索引到结尾,上面的i=index[n]可以看出          for (int i = index[n]; i < candidates.size(); ++i)          {              index[n+1] = i; // 记录当前考察的候选项索引              backtrace(target, sum+candidates[i], candidates, index, n+1);          }            // 深度搜索,为了避免重复,每次从当前候选项索引到结尾,上面的i=index[n]可以看出       //   for (int i = index[n]; i < candidates.size(); ++i)       //   {       //       index[n+1] = i+1;   // 记录当前考察的候选项索引并加一,下次考察是跳过上次考察过的元素,每轮每个元素值考察一次       //       backtrace(target, sum+candidates[i], candidates, index, n+1);       //   }      }      vector<vector<int> > combinationSum(vector<int> &candidates, int target) {          // Start typing your C/C++ solution below          // DO NOT write int main() function          sort(candidates.begin(), candidates.end());            int *index = new int[index_count];          memset(index, 0, sizeof(int)*index_count);                    results.clear();    // 提交到leetcode的测试系统上必须添加,它应该是使用一个对象测试所有测试用例。          backtrace(target, 0, candidates, index, 0);            delete[] index;            return results;      }  };
5> 给定只有1到9这9个数,选择k个数,它的和等于n。

      k=3,n=9.输出

[[1,2,6], [1,3,5], [2,3,4]]
class Solution {public:    vector<vector<int>> combinationSum3(int k, int n)     {        vector<int> temp;        sum(k,n,0,temp,0);        return res;    }        void sum(int k,int n,int f1,vector<int> temp,int m)    {        if(f1>n) return ;        if(f1==n && k==0) res.push_back(temp);        else        {            for(int i=1;i<10;i++)            {                if(i>m)                {                    //flag[i]=1;                    temp.push_back(i);                    sum(k-1,n,f1+i,temp,i);                    temp.pop_back();                    //flag[i]=0;                }                else                    continue;            }                        }    }private:    vector<vector<int>> res;    int flag[10]={0};};
6> 输出所有的括号对的个数

    例如n=3时。输出"((()))", "(()())", "(())()", "()(())", "()()()"

class Solution {public:    vector<string> generateParenthesis(int n)     {        string s;        generate(n,n,s,res);        return res;    }    void generate(int leftNum,int rightNum,string s,vector<string> &result)      {          if(leftNum==0&&rightNum==0)          {              result.push_back(s);          }          if(leftNum>0)          {              generate(leftNum-1,rightNum,s+'(',result);          }          if(rightNum>0&&leftNum<rightNum)          {              generate(leftNum,rightNum-1,s+')',result);          }      } private:    vector<string> res;};


0 0