棋子

导航

Combination Sum

题目链接:

回溯算法的剪枝非常重要!!

这个题是一个NP问题,方法仍然是N-Queens中介绍的套路。基本思路是先排好序,然后每次递归中把剩下的元素一一加到结果集合中,并且把目标减去加入的元素,然后把剩下元素(包括当前加入的元素)放到下一层递归中解决子问题。算法复杂度因为是NP问题,所以自然是指数量级的。

简单的回溯法(递归实现).

比如对于数组3,2,6,7,target = 7,对数组排序得到[2,3,6,7]

1、第1个数字选取2, 那么接下来就是解决从数组[2,3,6,7]选择数字且target = 7-2 = 5

2、第2个数字选择2,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 5-2 = 3

3、第3个数字选择2,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 3-2 = 1

4、此时target = 1小于数组中的所有数字,失败,回溯,重新选择第3个数字

5、第3个数字选择3,那么接下来就是解决从数组[2,3,6,7]选择数字且target = 3-3 = 0

6、target = 0,找到了一组解,继续回溯寻找其他解。

贴上代码:

#include <iostream>     // std::cout
#include <algorithm>    // std::is_heap_until, std::sort, std::reverse
#include <vector>       // std::vector
using namespace std;

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {

        vector<int> temp;
        sort(candidates.begin(), candidates.end());
        if (candidates.size() == 0)//还有candidates==NULL的情况
            return res;
        helper(candidates, 0, target, res, temp);//
        return res;
    }
    void show(){
        for (int i = 0; i < res.size(); i++)
        {
            for (int j = 0; j < res[i].size(); j++)
                cout << res[i][j] << " ";
            cout << endl;
        }
    }
private:
    void helper(vector<int>& candidates, int index, int target,vector<vector<int>>& res,vector<int>& temp){
        if (target < 0)
            return;
        if (0 == target){
            res.push_back(temp);
            return;
        }
        for (int i = index; i < candidates.size(); i++){  //这儿i=index,千万别再写成了i=0
            if (i>0 && candidates[i] == candidates[i - 1])
                continue;
            //if (candidates[i] <= target){//这儿不需要这一句,让其添加就好了,否则target就不会有变为负数的机会了
                temp.push_back(candidates[i]);
                target -= candidates[i];
                //helper(candidates, i, target, res, temp);//问题:这个target的值并没有随着递归返回而恢复原来的值
                helper(candidates, i, target, res, temp);
                target += candidates[i];  //这个地方也非常关键
                temp.pop_back();
            //}
        }
    }
private:
    vector<vector<int>> res;
};


int main() {
    vector<int> arr{1 };
    Solution test;
    test.combinationSum(arr, 1);
    test.show();

    return 0;
}

 

posted on 2016-03-08 21:17  鼬与轮回  阅读(146)  评论(0编辑  收藏  举报