目录
⼦集(medium)
题目解析
讲解算法原理
编写代码
找出所有⼦集的异或总和再求和(easy)
题目解析
讲解算法原理
编写代码
⼦集(medium)
题目解析
1.题目链接:. - 力扣(LeetCode)
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中的所有元素互不相同
讲解算法原理
解法:算法思路:
为了获得nums数组的所有⼦集,我们需要对数组中的每个元素进⾏选择或不选择的操作,即nums数组⼀定存在2^(数组⻓度)个⼦集。对于查找⼦集,具体可以定义⼀个数组,来记录当前的状态,并对其进⾏递归。
对于每个元素有两种选择:
1.不进⾏任何操作;
2.将其添加⾄当前状态的集合。在递归时我们需要保证递归结束时当前的状态与进⾏递归操作前的状态不变,⽽当我们在选择进⾏步骤2进⾏递归时,当前状态会发⽣变化,因此我们需要在递归结束时撤回添加操作,即进⾏回溯。
递归函数设计:voiddfs(vector<vector<int>>&res,vector<int>&ans,vector<int>&nums,intstep)
参数:step(当前需要处理的元素下标);
返回值:⽆;
函数作⽤:查找集合的所有⼦集并存储在答案列表中。
递归流程如下:
1. 递归结束条件:如果当前需要处理的元素下标越界,则记录当前状态并直接返回;
2. 在递归过程中,对于每个元素,我们有两种选择:
◦ 不选择当前元素,直接递归到下⼀个元素;
◦ 选择当前元素,将其添加到数组末尾后递归到下⼀个元素,然后在递归结束时撤回添加操作;3. 所有符合条件的状态都被记录下来,返回即可。
编写代码
c++算法代码:
// 解法⼀:
class Solution
{vector<vector<int>> ret;vector<int> path;
public:vector<vector<int>> subsets(vector<int>& nums) {dfs(nums, 0);return ret;}void dfs(vector<int>& nums, int pos){if(pos == nums.size()){ret.push_back(path);return;}// 选path.push_back(nums[pos]);dfs(nums, pos + 1);path.pop_back(); // 恢复现场// 不选dfs(nums, pos + 1);}
};
// 解法⼆:
class Solution
{vector<vector<int>> ret;vector<int> path;
public:vector<vector<int>> subsets(vector<int>& nums) {dfs(nums, 0);return ret;}void dfs(vector<int>& nums, int pos){ret.push_back(path);for(int i = pos; i < nums.size(); i++){path.push_back(nums[i]);dfs(nums, i + 1);path.pop_back(); // 恢复现场}}
};
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);}
}
// 解法⼆:
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){ret.add(new ArrayList<>(path));for(int i = pos; i < nums.length; i++){path.add(nums[i]);dfs(nums, i + 1);path.remove(path.size() - 1); // 恢复现场 }}
}
找出所有⼦集的异或总和再求和(easy)
题目解析
1.题目链接:. - 力扣(LeetCode)
2.题目描述
⼀个数组的异或总和定义为数组中所有元素按位XOR的结果;如果数组为空,则异或总和为0。例如,数组[2,5,6]的异或总和为2XOR5XOR6=1。
给你⼀个数组nums,请你求出nums中每个⼦集的异或总和,计算并返回这些值相加之和。注意:在本题中,元素相同的不同⼦集应多次计数。
数组a是数组b的⼀个⼦集的前提条件是:从b删除⼏个(也可能不删除)元素能够得到a。
• ⽰例1:
输⼊:nums=[1,3]输出:6
解释:[1,3]共有4个⼦集:• 空⼦集的异或总和是0。• [1]的异或总和为1。
• [3]的异或总和为3。• [1,3]的异或总和为1XOR3=2。0+1+3+2=6
• ⽰例2:
输⼊:nums=[5,1,6]输出:28
解释:[5,1,6]共有8个⼦集:• 空⼦集的异或总和是0。
• [5]的异或总和为5。
• [1]的异或总和为1。
• [6]的异或总和为6。
• [5,1]的异或总和为5XOR1=4。
• [5,6]的异或总和为5XOR6=3。
• [1,6]的异或总和为1XOR6=7。
• [5,1,6]的异或总和为5XOR1XOR6=2。
0+5+1+6+4+3+7+2=28
• ⽰例3:
输⼊:nums=[3,4,5,6,7,8]
输出:480
解释:每个⼦集的全部异或总和值之和为480。
• 提⽰:
1<=nums.length<=12
1<=nums[i]<=20
讲解算法原理
解法(递归):
算法思路:
所有⼦集可以解释为:每个元素选择在或不在⼀个集合中(因此,⼦集有 个)。本题我们需要求出所有⼦集,将它们的异或和相加。因为异或操作满⾜交换律,所以我们可以定义⼀个变量,直接记录当前状态的异或和。使⽤递归保存当前集合的状态(异或和),选择将当前元素添加⾄当前状态与否,并依次递归数组中下⼀个元素。当递归到空元素时,表⽰所有元素都被考虑到,记录当前状态(将当前状态的异或和添加⾄答案中)。
例如集合中的元素为[1,2],则它的⼦集状态选择过程如下:
[]
/ \
[] [1] //第⼀个元素选择与否
/ \ / \
[] [2] [1] [1, 2] //第⼆个元素选择与否,每个状态到这⼀层时需要记录异或和
递归函数设计:voiddfs(intval,intidx,vector<int>&nums)
参数:val(当前状态的异或和),idx(当前需要处理的元素下标,处理过程:选择将其添加⾄当前状态或不进⾏操作);
返回值:⽆;
函数作⽤:选择对元素进⾏添加与否处理。
递归流程:
1. 递归结束条件:当前下标与数组⻓度相等,即已经越界,表⽰已经考虑到所有元素;
a. 将当前异或和添加⾄答案中,并返回;
2. 考虑将当前元素添加⾄当前状态,当前状态更新为与当前元素值的异或和,然后递归下⼀个元素;
3. 考虑不选择当前元素,当前状态不变,直接递归下⼀个元素;
编写代码
c++算法代码:
class Solution
{int path;int sum;
public:int subsetXORSum(vector<int>& nums) {dfs(nums, 0);return sum;}void dfs(vector<int>& nums, int pos){sum += path;for(int i = pos; i < nums.size(); i++){path ^= nums[i];dfs(nums, i + 1);path ^= nums[i]; // 恢复现场}}
};
java算法代码:
class Solution
{int path;int sum;public int subsetXORSum(int[] nums) {dfs(nums, 0);return sum;}public void dfs(int[] nums, int pos){sum += path;for(int i = pos; i < nums.length; i++){path ^= nums[i];dfs(nums, i + 1);path ^= nums[i]; // 恢复现场}}
}