每天一道LeetCode-----找出给定序列的所有子序列
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-----找出给定序列的所有子序列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天一道LeetCode-----找到1
- 下一篇: 每天一道LeetCode-----移除有