90. Subsets II

经典题目,
跟LC78不一样的地方在于 (LC78见另外外一篇博文 https://www.jianshu.com/p/3b8fd52774f7
这里有重复,需要去重。
LC78 版本二的解法关键在于不要回头看。这次要去重,要求就又苛刻些。
这次关键在于不仅不能回头看,如果你错过风景了,遇到相同的风景也不再收入囊中了。
先来的元素有优先权,如果你遇到一对完全相同的元素,双胞胎,如果你没取第一个却取了第二个,是不是就重复了? 所以你要么取第一个, 要么取第一个和第二个,要么哪个也不取,你不能只取第二个,这两个元素有尊卑。其实元素本身没有尊卑,但为了去重我们故意给他们按照先来后到的顺序标了优先级。
另外外一种理解方法是每一层只能取该层多胞胎中的第一个。

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        List<List<Integer>> ans = new ArrayList<>();
        Arrays.sort(nums);
        subsetsWithDup(nums, 0, ans, new ArrayList<>());
        return ans;
    }
    private void subsetsWithDup(int[] nums, int index, 
                                List<List<Integer>> ans, List<Integer> curList ) {
        ans.add(new ArrayList<>(curList));
        for (int i = index; i < nums.length; i++) {
            if (i != index && nums[i] == nums[i - 1]) continue; //去重的关键在于此行
            curList.add(nums[i]);
            subsetsWithDup(nums, i + 1, ans, curList);
            curList.remove(curList.size() - 1);
        }
    }

C++版本

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        vector<int> cur;
        dfs(nums, ans, 0, cur);
        return ans;
    }
private:
    void dfs(const vector<int>& nums, vector<vector<int>>& ans, int index, vector<int>& cur) {
        ans.emplace_back(cur);
        if (index == nums.size()) return;
        for (int i = index; i < nums.size(); i++) {
            if (i != index && nums[i] == nums[i - 1]) continue;
            cur.push_back(nums[i]);
            dfs(nums, ans, i + 1, cur);
            cur.pop_back();
        }
    }
};

注意请轻易不要使用class variable。

这题我尝试使用 https://www.jianshu.com/p/3b8fd52774f7 的第一个版本基础上增加去重功能, 发现比较麻烦,做倒是可以做。
假设你有5个5,就是要数一数已经取过的5和见过的5是不是数量相等。如果不相等,主不要取5了, 如果相等可以取5,也可以不取5,这个比较麻烦,不容易写的漂亮。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容