回溯法——列举多维向量

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值