每天一道LeetCode-----获取无重复项/有重复项序列的全排列
原題鏈接Permutations
要求是輸出給定序列的全排列,序列中不包含重復元素
STL中有next_permutation函數可以獲取當前序列的下一個排列,使用起來也很簡單,先對序列按遞增順序排序,然后不斷調用next_permutation函數獲取當前序列的下一個更大的排列,如果沒有更大的排列就返回false
這里主要是利用另一種方法實現,做個記錄
對于全排列問題,又是沒有重復項的序列,可以采用不斷交換兩個位置的方法獲得所有的排列,即以某個點為開始點,依次和后面的做交換,因為沒有重復項,所以得到的序列都是不同的結果,例如
但是這種方法少了一種結果,{1 3 2} 。因為序列{1 2 3}的時候是以1為開始點,但是沒有對2和3進行交換。原因在于沒有從{1 2 3}遞歸并且開始點是第二個數的過程。所以,解決辦法就是當開始點進行交換時,也要和自己交換一次,但是交換的結果不能添加到結果中。但是這樣對于第一個序列{1 2 3}就不在結果中,所以需要在交換前手動添加第一個序列。
代碼如下
擴展
Permutations II
原題鏈接Permutations II
和上面要求一樣,唯一區別是給定的序列可能有重復的元素
如果再按照上面的方法,那么會出現大量重復的結果,比如第一個1和第二個1交換,結果沒有變換,但是被添加了兩次。所以,在進行交換的時候,需要特別注意,以當前位置作為開始點和后面的元素進行交換時,這個元素在之前有沒有交換過,如果交換過了,就不用再交換了。
例如,如果開始時序列為{1 2 7 7 9},某次交換以2為開始點
原因就在于如果有重復的元素,那么開始點第一次和重復元素的第一個元素交換,接著和第二個元素交換獲取的排列,和開始點直接和重復元素的第二個元素交換獲取的排列是一樣的
所以,只需要和重復元素的第一個元素交換一次即可,后面重復的元素都不需要再次交換,因為在向后遞歸的過程中,開始點和后面的重復元素已經交換過了。
代碼如下
class Solution { public:vector<vector<int>> permuteUnique(vector<int>& nums) {/* 遞增排序 */std::sort(nums.begin(), nums.end());vector<vector<int>> res;/* 添加原始排列 */res.push_back(nums);get_permutation(nums, 0, res);return res;} private:void get_permutation(vector<int>& nums, int idx, vector<vector<int>>& res){if(idx >= nums.size())return;/* 記錄是否有交換過 */std::unordered_set<int> hash;for(int i = idx; i < nums.size(); ++i){if(hash.find(nums[i]) != hash.end())continue;hash.insert(nums[i]);swap(nums[i], nums[idx]);if(i != idx)res.push_back(nums);get_permutation(nums, idx + 1, res);swap(nums[i], nums[idx]);}} };總結
以上是生活随笔為你收集整理的每天一道LeetCode-----获取无重复项/有重复项序列的全排列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天一道LeetCode-----重新实
- 下一篇: 每天一道LeetCode-----找到第