216. Combination Sum III

来源:互联网 发布:bad rabbit勒索软件 编辑:程序博客网 时间:2024/06/05 16:21

  • Combination Sum III
    • 题目解析
    • 代码实现
  • radix sort

216. Combination Sum III

题目解析

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.Example 1:Input: k = 3, n = 7Output:[[1,2,4]]Example 2:Input: k = 3, n = 9Output:[[1,2,6], [1,3,5], [2,3,4]]

就是在1~9中取k个数字,不能重复。使得k个数的和为n的组合存进数组并返回。

这里我使用的是暴力破解,根据最后一个数字的索引来迭代求和,如果到了尽头那么就把前一位的索引加一。如果前一位还是有进位,那么就继续进位,直到没有进位。然后把最后一位进位的索引后面的索引排在它的后面,然后往复进行。

代码实现

暴力破解:

class Solution {public:    __inline int calculateSum(vector<int> ind, int num) {        int res = 0;        for(int i = 1; i <= num; i++) res += ind[i];        return res;    }     vector<vector<int>> combinationSum3(int k, int n) {        vector<vector<int>> res;        vector<int> ind(10, 0);        if(k > 9 || n > 45) return res;        for(int i = 1; i <= 9; i++) ind[i] = i;        while(ind[1] <= 10 - k) {            while(ind[k] <= 9) {                int cur_sum = calculateSum(ind, k);                if(cur_sum == n)  res.push_back(vector<int>(ind.begin()+1, ind.begin()+k+1));                else if(cur_sum > n) { ind[k] = 10;  break; }                ind[k]++;            }            if(ind[1] == 10 - k) break;            int stt = k-1;            while(stt >= 1) {                ind[stt] += 1;                if(ind[stt] <= 10 + stt - k) break;                else {                    stt--;                }                }            for(int i = stt+1; i <= k; i++) ind[i] = ind[i-1] + 1;         }        return res;    }};

改进前面的做法,使用夹逼来做这道题目,前后两个部分的数字数目一样,然后遇到条件一样的时候就把两个都做计算。使用这种方法结果是超时,当然这种做法确实有bug。

class Solution {public:    __inline int calculateSum(vector<int> ind, int num) {        int res = 0;        for(int i = 1; i <= num; i++) res += ind[i];        return res;    }     vector<vector<int>> combinationSum3(int k, int n) {        vector<vector<int>> res;        set<vector<int>> tmp;        vector<int> ind(10, 0);        vector<int> ind2(10, 0);        if(k > 9 || n > 45) return res;        int half = k >> 1, cnt = 1, cur_sum = 0;        for(cnt = 1; cnt <= half + (1&k); cnt++) ind[cnt] = cnt;        for(int i = 10 - half; i <= 9; i++)  ind[cnt++] = i;        queue<vector<int>> stk;        stk.push(ind);        while(!stk.empty()) {            ind = stk.front();            stk.pop();            while(ind[half] < ind[half+1]) {                int h1 = ind[half], h2 = ind[half+1];                ind2 = ind;                while(ind[half] < ind[half+1]) {                    cur_sum = calculateSum(ind, k);                    if(cur_sum == n)  { tmp.insert(vector<int>(ind.begin()+1, ind.begin()+k+1)); ind[half]++; ind[half+1]--; }                    else if(cur_sum > n)  ind[half+1]--;                      else ind[half]++;                }                if(ind[k] - ind[1] <= k - 1) break;                int stt = 0;                if(cur_sum < n) {                    stt = half - 1;                    ind[half+1] = h2;                    while(stt >= 1) {                        ind[stt]++;                        if(ind[half+1] - ind[stt] >= half + 1 - stt) break;                        else  stt--;                    }                    for(int i = stt+1; i <= half; i++) ind[i] = ind[i-1] + 1;                }                  else if(cur_sum > n){                    stt = half + 2;                    ind[half] = h1;                    while(stt <= k) {                        ind[stt]--;                        if(ind[stt] - ind[half] >= stt - half) break;                        else  stt++;                    }                    for(int i = stt-1; i >= half+1; i--) ind[i] = ind[i+1] - 1;                }                else {                    // part 1                    stt = half - 1;                    ind[half+1] = h2;                    while(stt >= 1) {                        ind[stt]++;                        if(ind[half+1] - ind[stt] >= half + 1 - stt) break;                        else  stt--;                    }                    for(int i = stt+1; i <= half; i++) ind[i] = ind[i-1] + 1;                    // part 2                    stt = half + 2;                    while(stt <= k) {                        ind2[stt]--;                        if(ind2[stt] - ind2[half] >= stt - half) break;                        else  stt++;                    }                    for(int i = stt-1; i >= half+1; i--) ind2[i] = ind2[i+1] - 1;                    stk.push(ind2);                }            }        }        return vector<vector<int>>(tmp.begin(), tmp.end());    }};

然后是DFS的做法,我们从9个数字中取k个数字,然后每个数字就是取或者没有取。这个代码的效率比第一种做法高了很多。

class Solution {public:    void backTrack(vector<vector<int>>&res, int target, int num, vector<int> &tmp, int stt) {        int sz = tmp.size(), cur_sum = accumulate(tmp.begin(), tmp.end(), 0);        if(tmp.size() == num) {            if(cur_sum == target) res.push_back(tmp);            return;        }        if(cur_sum >= target) return;        if(9 - stt + 1 >= num - sz) {            tmp.push_back(stt);            backTrack(res, target, num, tmp, stt+1);            tmp.pop_back();            backTrack(res, target, num, tmp, stt+1);        }    }     vector<vector<int>> combinationSum3(int k, int n) {        vector<vector<int>> res;        vector<int> ind;        if(k > 9 || n > 45) return res;        backTrack(res, n, k, ind, 1);        return res;    }};

使用回溯,可以更加节约空间,但是速度上没有比DFS快,会差一点点。

class Solution {public:    void backTrack(vector<vector<int>>&res, int target, int num, vector<int> &tmp, int stt) {        int sz = tmp.size(), cur_sum = accumulate(tmp.begin(), tmp.end(), 0);        if(tmp.size() == num) {            if(cur_sum == target) res.push_back(tmp);            return;        }        if(cur_sum >= target) return;        if(9 - stt + 1 >= num - sz) {            for(int i = stt; i <= 9; i++) {                tmp.push_back(i);                backTrack(res, target, num, tmp, i+1);                tmp.pop_back();            }        }    }     vector<vector<int>> combinationSum3(int k, int n) {        vector<vector<int>> res;        vector<int> ind;        if(k > 9 || n > 45) return res;        backTrack(res, n, k, ind, 1);        return res;    }};

radix sort

经典排序算法 - 基数排序Radix sort

原理类似桶排序,这里总是需要10个桶,多次使用

首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,暂时忽视十位数

例如:

待排序数组[62,14,59,88,16]简单点五个数字

分配10个桶,桶编号为0-9,以个位数数字为桶编号依次入桶,变成下边这样

| 0 | 0 | 62 | 0 | 14 | 0 | 16 | 0 | 88 | 59 |

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶编号

将桶里的数字顺序取出来,

输出结果:[62,14,16,88,59]

再次入桶,不过这次以十位数的数字为准,进入相应的桶,变成下边这样:

由于前边做了个位数的排序,所以当十位数相等时,个位数字是由小到大的顺序入桶的,就是说,入完桶还是有序

| 0 | 14,16 | 0 | 0 | 0 | 59 | 62 | 0 | 88 | 0 |

| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |桶编号

因为没有大过100的数字,没有百位数,所以到这排序完毕,顺序取出即可

最后输出结果:[14,16,59,62,88]

参考链接:http://www.cnblogs.com/kkun/archive/2011/11/23/2260275.html

0 0
原创粉丝点击