78. Subsets

题目链接:
https://leetcode.com/problems/subsets/description/

题目描述:

Given a set of distinct integers, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

Example:

Input: nums = [1,2,3]
Output:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]

这个题目是在n个数中选(0到n)个数有多少种不同的方法,其实还是选或不选的问题,和77. Combinations本质上是一样的,而且笔者之前在这篇文章中总结了此类问题的套路,读者可以点进去看看。

下边是这个问题的解法

代码一

相关知识: 排列公式Anm是指从n个元素取m个进行排列(即排序)
组合公式Cnm是指从n个元素取m个不进行排列(即不排序)

这个相当于是组合公式,由例子来说,相当于是从3个数取数,由多少种取法,这里是2的3次方,相当于8种方法。如果输入为N个元素,则有2的n次方中方法。

该题相当于顺序遍历该列表中的元素,每个元素取或者不取。下图是该问题的图解,每个二叉树的分支,左孩子表示选择该元素,有孩子表示不选。

这里写图片描述

代码如下:

class Solution {
public List<List<Integer>> subsets(int[] nums) {

        if(nums == null || nums.length == 0) {
            return new ArrayList<List<Integer>>();
        }
        List<List<Integer>> ans = new ArrayList<>();
        backtrack(ans, new ArrayList<Integer>(), nums, 0);
        return ans;
    }

    private void backtrack(List<List<Integer>> ans, List<Integer> list, int[] nums, int index) {
        if(index >= nums.length) {
            ans.add(new ArrayList<Integer>(list));
            return;
        }

        list.add(nums[index]);
        backtrack(ans, list, nums, index+1);
        list.remove(list.size() - 1);
        backtrack(ans, list, nums, index+1);

        return;
    }
}

代码二

上述代码结构笔者比较喜欢的回溯方法,因为比较容易理解,下边的代码是笔者之前经常弄混的回溯法的另一种方法,下边的代码在leecode上提交之后也AC,其实代码一和代码二非常的相似,但是有下边几点不同:

  1. 代码二的for循环里,只有一个回溯,而代码一里有两个回溯。
  2. 代码二每次回溯的开头就将答案保存,而代码一需要在结尾的时候保存答案。

为什么代码二里有两个回溯,而代码一里只有一个回溯呢?因为代码二是一个for循环,这个循环相当于遍历了树的每一层,因此remove之后不用再回溯,相当于这一层不选,然后for至下一层,再判断是否选择。

个人推荐代码一,好懂!

class Solution {
public List<List<Integer>> subsets(int[] nums) {

        if(nums == null || nums.length == 0) {
            return new ArrayList<List<Integer>>();
        }
        List<List<Integer>> ans = new ArrayList<>();
        backtrack(ans, new ArrayList<Integer>(), nums, 0);
        return ans;
    }

    private void backtrack(List<List<Integer>> ans, List<Integer> list, int[] nums, int index) { 

        ans.add(new ArrayList<Integer>(list)); 

        for(int i = index; i < nums.length; i++) {
            list.add(nums[i]);
            backtrack(ans, list, nums, i+1);
            list.remove(list.size() - 1);
        }       

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值