leetcode-78-Subsets

问题

题目:[leetcode-78]

思路

按照层次进行枚举即可。主要剪枝的条件。
1. 当前元素之前不能出现过
2. 必须是升序

注意状态恢复。

代码

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> ret;
        vector<int> arr;
        ret.push_back(arr);

        set<int> visited;
        int sz = nums.size();
        if(!sz) return ret;

        dfs( arr, visited, nums, sz, ret );

        return ret;
    }
private:
    void dfs( vector<int>& arr, set<int>& visited, vector<int>& nums, int n, vector<vector<int>>& ret ){
        if( arr.size() == n ) return;
        else{
            for(int i = 0; i < n; ++i){
                if( visited.find(nums[i]) != visited.end() ) continue;
                int sz = arr.size();
                bool legal = true;
                for(int k = 0; k < sz; ++k){
                    if( arr[k] >= nums[i] ){
                        legal = false;
                        break;
                    }
                }
                if(!legal) continue;

                arr.push_back(nums[i]);
                visited.insert(nums[i]);

                ret.push_back(arr);
                dfs( arr, visited, nums, n, ret );

                arr.pop_back(); // 状态恢复
                visited.erase( nums[i] ); // 状态恢复              
            }
        }
    }
};

后记

判断一个数组是否可以两分,正解应该在这里。
背包看起来好像可以解决,但是由于背包要求的是不超过V的条件下,最大的价值。所以它没法精确。

看一道题目:

在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为A[i]

注意事项

你不可以将物品进行切割。

注意这到题目,这到题目其实并不是标准的背包。此时,它的容量和价值一样。所以,问你在给定V的条件下,最多装多满。此时,价值和容量一样。

如果有4个物品[2, 3, 5, 7]

如果背包的大小为11,可以选择[2, 3, 5]装入背包,最多可以装满10的空间。

如果背包的大小为12,可以选择[2, 3, 7]装入背包,最多可以装满12的空间。

函数需要返回最多能装满的空间大小。

这个题目也可以换个问法:

对于数组[2,3,5,7],如果不超过11,数组中挑出几个数所能形成的最大值应该是多少。
当然,可以采用上面的办法,枚举所有子集,把小于11的拿出来。比以下最大值。
背包的思想也可以使用,在不超过容量11的前提下。获取的最大价值。此时,价值和容量的值是一样的。

但是,如果问数组是否可以等分。以上面的题目为例,那就是是否可以找到一个子集,它的和为8.5。如果是背包,只能用容量做上限。没法精确,这就是问题。

代码2

改进了visted用下标进行标记。

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> arr;
        vector<vector<int>> ret;
        ret.push_back(arr);
        set<int> visited;

        dfs( arr, visited, nums, nums.size(), ret );
        return ret;
    }
private:
    void dfs(vector<int>& arr, set<int>& visited, vector<int>& nums, int n, vector<vector<int>>& ret ){
        if( arr.size() == n ) return;
        else{
            for(int i = 0; i < n; ++i){
                if( visited.find(i) != visited.end() ) continue;
                int sz = arr.size();
                bool flag = true;
                for( int k = 0; k < sz; ++k ){
                    if( arr[k] > nums[i] ){ flag = false; break; }
                }
                if(!flag) continue;

                arr.push_back( nums[i] );
                visited.insert( i );
                ret.push_back(arr);
                dfs( arr, visited, nums, n, ret );
                arr.pop_back();
                visited.erase(i);
            }
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值