每天一道LeetCode-----找出给定序列的所有子序列
2017-12-10 19:35
253 查看
Subsets
原题链接Subsets给定一个数组序列,找出所有子序列
深度优先扫一遍:)
class Solution { public: vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> res; vector<int> cur; dfs(0, nums, cur, res); return res; } private: void dfs(int i, vector<int>& nums, vector<int>& cur, vector<vector<int>>& res) { res.emplace_back(cur); if(i >= nums.size()) return; for(int j = i; j < nums.size(); ++j) { cur.push_back(nums[j]); dfs(j + 1, nums, cur, res); cur.pop_back(); } } };
原题链接Subsets II
找到给定序列的所有子序列,给定的序列中可能会包含重复元素
解题时需要注意几个地方
容我好好吐槽一下,根本没有说明好伐:(
最后的结果中子序列的顺序无要求,即[1,2,3]和[3,2,1]是相同的
对于重复元素,第二条规定尤为重要,即[4,4,4,1]和[4,4,1,4]是相同的
更重要的是,对于第三条,[1,4,4,4]和[4,4,4,1]以及[4,4,1,4]同样是相同的
用[1,2,3]代替[3,2,1]以及用[1,4,4,4]代替[4,4,1,4]是什么概念,就是说所有子序列可以都是递增的,再往上想就是可以事先对给定序列排序,那解决重复问题就简单多了
在Subsets中,通过深度优先找到了所有的子序列,但是如果序列中有重复元素,需要添加几个限制条件
以序列[4,4,4,1,4]举例,如果不添加限制条件,那么最后的结果可能存在
[4,4,4,1],[4,4,1,4]以及[4,1],[1,4]以及[4,4,4],[4,4,4]
毫无疑问上面二个都是相同的,即结果中出现重复元素,不符合要求
深度优先和回溯在解决重复问题时通常是在下次递归之前判断当前要添加到结果集中的元素是否应该被添加到结果集中,针对Subsets的模板
class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { //std::sort(nums.begin(), nums.end()); vector<vector<int>> res; vector<int> cur; dfs(nums, 0, cur, res); return res; } private: void dfs(vector<int>& nums, int i, vector<int>& cur, vector<vector<int>>& res) { res.emplace_back(cur); for(int j = i; j != nums.size(); ++j) { //判断是否应该添加到结果集中 if(...) { cur.emplace_back(nums[j]); dfs(nums, j + 1, cur, res); cur.pop_back(); } } } };
方法就是判断nums[j]是否在[i : j-1]这个范围内出现过,考虑当前遍历到[1,4,4,4,4] (已排序)的下标1(即元素4的位置),在回溯之后遍历的下标改为2(即第二个元素4的位置),这就会重复
因为在遍历第一个4时进入深度优先递归,在递归的过程中已经将所有组合可能都记录到结果中,其中就包括下标组合[1,3,4],那和第二次递归的下标组合[2,3,4]其实是一样的,结果都是[4,4,4]
原因是对于任何重复的元素,只需要考虑第一个即可,假设i, i+1, i+2, …, k是重复元素,那么选择nums[i]和选择nums[i+2]是一样的,因为选择nums[i]时,可以假设递归时不选择nums[i+1],那么就和直接选择nums[i+2]一样了
代码如下
class Solution { public: vector<vector<int>> subsetsWithDup(vector<int>& nums) { std::sort(nums.begin(), nums.end()); vector<vector<int>> res; vector<int> cur; dfs(nums, 0, cur, res); return res; } private: void dfs(vector<int>& nums, int i, vector<int>& cur, vector<vector<int>>& res) { res.emplace_back(cur); for(int j = i; j != nums.size(); ++j) { if(j == i || nums[j] != nums[j - 1]) { cur.emplace_back(nums[j]); dfs(nums, j + 1, cur, res); cur.pop_back(); } } } };
相关文章推荐
- 每天一道LeetCode-----给定序列中2/3/4个元素的和为target的所有集合,或3个元素的和最接近target的集合
- 每天一道LeetCode-----找到给定序列中所有和为某个值的集合或集合个数,序列中可以有/无重复项,集合元素顺序不同算不同集合等
- 每天一道LeetCode-----计算给定序列中所有长度为k的滑动窗的最大值集合
- 每天一道LeetCode-----将字符串切分成若干单词,使得每个单词都在给定的字典中,求出所有的切分结果
- 每天一道LeetCode-----计算给定范围内所有数的与运算结果
- 每天一道LeetCode-----找到二叉树所有和为给定值的路径
- 每天一道LeetCode-----给定一个矩阵,如果某个元素是0,就将所在行所在列上所有元素否置0
- 每天一道LeetCode-----二叉树逐层遍历,每一层存在一个序列中,返回所有序列集合
- 每天一道LeetCode-----在给定序列中找到满足nums[i]>nums[i-1]&&nums[i]>nums[i+1]的位置,要求时间复杂度是O(logN)
- 每天一道LeetCode-----一个整数序列,每个元素出现两次,只有一个(两个)出现一次,找到这个(这两个)元素
- leetcode-java.T015_3Sum---给定一个n个元素的数组,是否存在a,b,c三个元素,使用得a+b+c=0,找出所有符合这个条件的三元组
- 每天一道LeetCode-----找到有多少条连续路径的和为给定值,路径不需要从根节点出发到达叶子节点
- 每天一道LeetCode-----计算字符串s中有多少个子序列和字符串t相等
- 每天一道LeetCode-----给定字符串s和字符数组words,在s中找到words出现的位置,words内部字符串顺序无要求
- 每天一道LeetCode-----找到1,2,...,n这n个数所有的组合,每个组合有k个元素,且元素大小递增
- 每天一道LeetCode-----给定二维数组代表海域和岛屿,计算有多少个孤岛
- 每天一道LeetCode-----以字符串的形式输出二叉树所有从根节点到叶子节点的路径
- 每天一道LeetCode-----计算最长的元素连续序列长度
- 每天一道LeetCode-----计算二叉树所有根节点到叶子节点的和
- 每天一道LeetCode-----判断给定字符串是否符合某个模式