1.题目链接:
2.题目描述:
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
• 示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
• 示例 2:
输入:nums = [0]
输出:[[],[0]]
• 提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums 中的所有元素 互不相同
3. 解法:
算法思路:
为了获得 nums 数组的所有子集,我们需要对数组中的每个元素进行选择或不选择的操作,即 nums 数组一定存在 2^(数组长度) 个子集。对于查找子集,具体可以定义一个数组,来记录当前的状态,并对其进行递归。
对于每个元素有两种选择:1. 不进行任何操作;2. 将其添加至当前状态的集合。在递归时我们需要保证递归结束时当前的状态与进行递归操作前的状态不变,而当我们在选择进行步骤 2 进行递归时,当前状态会发生变化,因此我们需要在递归结束时撤回添加操作,即进行回溯。
递归函数设计:void dfs(vector<vector<int>>& res, vector<int>& ans, vector<int>& nums, int step)
参数:step(当前需要处理的元素下标);
返回值:无;
函数作用:查找集合的所有子集并存储在答案列表中。
递归流程如下:
1. 递归结束条件:如果当前需要处理的元素下标越界,则记录当前状态并直接返回;
2. 在递归过程中,对于每个元素,我们有两种选择:
◦不选择当前元素,直接递归到下一个元素;
◦选择当前元素,将其添加到数组末尾后递归到下一个元素,然后在递归结束时撤回添加操作;
3. 所有符合条件的状态都被记录下来,返回即可。
Java算法代码:
class Solution {
List<List<Integer>> ret;
List<Integer> path;
public List<List<Integer>> subsets(int[] nums) {
ret = new ArrayList<>();
path = new ArrayList<>();
dfs(nums, 0);
return ret;
}
public void dfs(int [] nums,int pos) {
if(pos == nums.length) {
ret.add(new ArrayList<>(path));
return;
}
//选
path.add(nums[pos]);
dfs(nums,pos+1);
path.remove(path.size() - 1);
// 不选
dfs(nums,pos+1);
}
}
代码结果:
递归展开:
这里笔者也是部分展开,建议,读者自行去进行展开。这里并不像前面那样使用函数的返回值去剪枝,而是手动来进行(其中有一行代码),建议往下看,后面逻辑展开,可以对减枝有更好的理解。
逻辑展开:
---------------------------------------------------------------------------------------------------------------------------------
记住,相信你的递归函数,它可以做到!
记住,不理解时候,去尝试手动展开!
记住,逻辑展开(你不可能对所有的题目都进行手动展开)!