leetcode题解日练--2016.7.18

日练三题,冰冻三尺非一日之寒。

今日题目:1、子集;2、组合加法;3、组合加法II 。

今日摘录:

世上只有一本书就是你,别的书,都是它的注释。
——顾城 《顾城哲思录》

78. Subsets | Difficulty: Medium

Given a set of distinct integers, nums, return all possible subsets.
Note: The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

题意:找出一个集合的所有子集。

思路:
1、找一个集合中的子集,一个n个元素的集合,它的子集个数有2的n次方种,好像联想到了什么,没错,2^n种可能性正好可以用n位2进制数来表示,而且每一位的意义都很好解释,就是集合中相对应的位置的元素有和没有两种情况。
这里如果要求子集是有顺序的,那么之前应该先进行一次排序操作,否则就无需做排序。看题目给的示例是从小到大的,那么我们就先对集合元素进行排序,然后再找子集。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int elem_nums = nums.size();
        int sub_nums = pow(2,elem_nums);
        vector<vector<int>> res(sub_nums,vector<int>());
        for(int i=0;i<elem_nums;i++)
        {
            for(int j=0;j<sub_nums;j++)
            {
                //第j个子集的第i位是1
                if((j>>i)&1)        res[j].push_back(nums[i]);
            }
        }
        return res;
    }
};

结果:8ms

2、迭代去做,最开始res是[[]],遍历一次我们的集合,然后对于res的每一个元素,都对其加上遍历到的元素。这样第一次遍历之后1个元素变成2个元素,第二次遍历之后2个元素变成4个元素,第三次4个元素变成8个元素。正好是我们需要的,能这么想代码就已经不是问题了。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> res(1,vector<int>());
        //遍历每个集合中的元素
        for(int i=0;i<nums.size();i++)
        {
            //在每次遍历的时候确认一下之后的结果集合有多大
            int size = res.size();
            //对于之前已经得到的结果,首先复制一份一样的,然后再对其加入新遍历的元素。
            for(int j=0;j<size;j++)
            {
                res.push_back(res[j]);
                res.back().push_back(nums[i]);
            }
        }
        return res;
    }
};

结果:8ms

3、题目的tag提示可以用回溯

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> res;
        vector<int> tmp;
        dfs(nums,res,0,tmp);
        return res;
    }
    void dfs(const vector<int>&nums,vector<vector<int> >& res,int length,vector<int>&tmp)
    {
        res.push_back(tmp);
        for(int i=length;i<nums.size();i++)
        {
            tmp.push_back(nums[i]);
            dfs(nums,res,i+1,tmp);
            tmp.pop_back();
        }
    }
};

结果:8ms

39. Combination Sum | Difficulty: Medium

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.

For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[
[7],
[2, 2, 3]
]

题意:从一个集合中挑选一些和为target的数组成新的集合。
相关题目:Combination Sum III
思路:
1、还是回溯,套用回溯的模板

class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> res;
        vector<int> tmp;
        dfs(candidates,target,res,tmp,0);    
        return res;
    }
    void dfs(const vector<int>candidates,int target,vector<vector<int>>&res,vector<int>&tmp,int begin)
    {
        if(!target)
        {
            res.push_back(tmp);
            return;
        }
        for(int i=begin;i!=candidates.size()&&target>=candidates[i];i++)
        {
            tmp.push_back(candidates[i]);
            dfs(candidates,target-candidates[i],res,tmp,i);
            tmp.pop_back();
        }
    }
};

结果:24ms

40. Combination Sum II | Difficulty: Medium

Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums toT.
Each number in C may only be used once in the combination.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.

For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]

题意:和前面题目很类似,区别在于集合中的元素只能用一次而不是多次。
思路:
1、和前面的题目都是一个模板,因此需要加一些限制条件就行了。
原本答案应该是:[[1,1,6],[1,2,5],[1,7],[2,6]],
返回的答案变成了:[[1,1,6],[1,2,5],[1,7],[1,2,5],[1,7],[2,6]]
问题在哪里呢?没错,有2个1,然后以第二个1开始的时候产生的组合会与之前的产生重复,可以采用集合来存储就能去重,但是还有更好的办法就是价一个判断条件,那么这个条件是什么呢?显然就要对阵下药,如果一个元素既不是开头元素,同时还与它前一个元素相同,这个时候就是遇到了连续两个相同元素,第二个应该跳过,只要在之前的代码中加一句if(i==begin||candidates[i]!=candidates[i-1])在dfs递归调用之前就可以了。

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> res;
        vector<int> tmp;
        dfs(candidates,target,res,tmp,0);
        return res;
    }
    void dfs(const vector<int>&candidates,int target,vector<vector<int>>& res,vector<int>&tmp,int begin)
    {
        if(!target)
        {
            res.push_back(tmp);
            return ;
        }
        if(target<0)    return;
        for(int i=begin;i!=candidates.size()&&target>=candidates[i];i++)
        {
            if(i==begin||candidates[i]!=candidates[i-1])
            {
            tmp.push_back(candidates[i]);
            dfs(candidates,target-candidates[i],res,tmp,i+1);
            tmp.pop_back();
            }
        }
    }
};

结果:12ms

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值