Leetcode 39 - Combination Sum I, II, III(dfs)

Combination Sum I

题意

给一个set C,然后还有一个你要凑出来的数target,要求C里面的数可以使用任意多次,求方案(输出具体方案)。

思路

先将数组从大到小排序(cut),然后开始搜索。
注意dfs模型:

void dfs(int pos, vector<int> tmp, int sum) {
    if (Boundary) {
        //ok, time to judge
        return;
    }
    //not choose this num
    dfs(pos + 1, tmp, sum);
    //choose this num
    tmp.push_back(a[pos]);
    dfs(pos, tmp, sum + a[pos]); // it may be choose again, so position is still this position.
    tmp.pop_back();
}

代码

int tot, n, aim;
vector<vector<int> > res;

class Solution {
public:
    void dfs(int pos, vector<int> tmp, vector<int>&a, int sum) {
        if (sum >= aim || pos == a.size()) {
            if (sum == aim) {
                tot++;
                res.push_back(tmp);
            } 
            return;
        }
        dfs(pos + 1, tmp, a, sum);
        tmp.push_back(a[pos]);
        dfs(pos, tmp, a, sum + a[pos]);
        tmp.pop_back();
    }

    vector<vector<int>> combinationSum(vector<int>& a, int target) {
        tot = 0; res.clear(); aim = target; //init
        sort(a.begin(), a.end(), greater<int>());
        vector<int> tt;
        dfs(0, tt, a, 0);
        return res;
    }
};

Combination Sum II

题意

给定一个数组,数组内可能有重复元素,然后再给一个target,要求用数组内的数凑出target(结果不能有重复)

思路

基本和上面那道题一样,但是存在一个陷阱就是数组内的元素有重复元素但是结果不能有重复元素,比如我们数组为[4, 1, 1],要凑出来5,结果应该是[4, 1]而不是[[4, 1], [4, 1]]。因此我们要对这种情况进行处理。

开始的时候用的一个很暴力的方法,直接用set套vector乱搞了一下。这样也对,但是时间复杂度会多一个log。比较好的方法是:当我们有2个1时,前面的1用了当前的1才能用。所以只需要加上这样一个判断就好了。

代码

//algorithm 1
int tot, n, aim;
vector<vector<int>> res;
set<vector<int>> tof;

class Solution {
public:
    void dfs(int pos, vector<int> tmp, vector<int>&a, int sum) {
        if (sum >= aim || pos == a.size()) {
            if (sum == aim) {
                tot++;
                if (tof.find(tmp) != tof.end()) return;
                tof.insert(tmp);
                res.push_back(tmp);
            }
            return;
        }
        dfs(pos + 1, tmp, a, sum);
        tmp.push_back(a[pos]);
        dfs(pos + 1, tmp, a, sum + a[pos]);
        tmp.pop_back();
    }

    vector<vector<int>> combinationSum2(vector<int>& a, int target) {
        tot = 0; res.clear(); aim = target; tof.clear();//init
        sort(a.begin(), a.end(), greater<int>());
        vector<int> tt;
        dfs(0, tt, a, 0);
        return res;
    }
};


//algorithm 2
int tot, n, aim;
vector<vector<int>> res;
int use[100005];
class Solution {
public:
    void dfs(int pos, vector<int> tmp, vector<int>&a, int sum) {
        if (sum >= aim || pos == a.size()) {
            if (sum == aim) {
                tot++;
                res.push_back(tmp);
            }
            return;
        }
        dfs(pos + 1, tmp, a, sum);
        if (pos > 0 && a[pos] == a[pos - 1]) {
            if (use[pos - 1]) {
                use[pos] = 1;
                tmp.push_back(a[pos]);
                dfs(pos + 1, tmp, a, sum + a[pos]);
                tmp.pop_back();
                use[pos] = 0;
            }
        } else {
            use[pos] = 1;
            tmp.push_back(a[pos]);
            dfs(pos + 1, tmp, a, sum + a[pos]);
            tmp.pop_back();
            use[pos] = 0;
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& a, int target) {
        tot = 0; res.clear(); aim = target;//init
        memset(use, 0, sizeof(use)); //init 
        sort(a.begin(), a.end(), greater<int>());
        vector<int> tt;
        dfs(0, tt, a, 0);
        return res;
    }
};

Combination Sum III

题意

给出一个k和n,要求用k个数(每个数属于1~9)来组成n。每个数只能用一次,并且结果不能重复。

思路

还是裸dfs,只是需要记录一下用了几个数

代码

vector<vector<int>> res;
int target, kk;

class Solution {
public:
    int a[10];

    void init(int n, int k) {
        res.clear();
        target = n;
        kk = k;
        for (int i = 0; i <= 9; i++) a[i] = i;
    }

    void dfs(int pos, int cnt, vector<int> tmp, int sum) {
        if (pos == 0 || sum >= target || cnt >= kk) {
            if (sum == target && cnt == kk) res.push_back(tmp);
            return;
        }
        dfs(pos - 1, cnt, tmp, sum);
        tmp.push_back(a[pos]);
        dfs(pos - 1, cnt + 1, tmp, sum + a[pos]);
        tmp.pop_back();
    }

    vector<vector<int>> combinationSum3(int k, int n) {
        init(n, k);
        vector<int> tmp;
        dfs(min(n, 9), 0, tmp, 0);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值