日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

每天一道LeetCode-----获取无重复项/有重复项序列的全排列

發布時間:2024/4/19 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 每天一道LeetCode-----获取无重复项/有重复项序列的全排列 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原題鏈接Permutations

要求是輸出給定序列的全排列,序列中不包含重復元素
STL中有next_permutation函數可以獲取當前序列的下一個排列,使用起來也很簡單,先對序列按遞增順序排序,然后不斷調用next_permutation函數獲取當前序列的下一個更大的排列,如果沒有更大的排列就返回false

class Solution { public:vector<vector<int>> permute(vector<int>& nums) {std::sort(nums.begin(), nums.end());vector<vector<int>> res;res.emplace_back(nums);}while(next_permutation(nums.begin(), nums.end()));return res;} };

這里主要是利用另一種方法實現,做個記錄
對于全排列問題,又是沒有重復項的序列,可以采用不斷交換兩個位置的方法獲得所有的排列,即以某個點為開始點,依次和后面的做交換,因為沒有重復項,所以得到的序列都是不同的結果,例如

1 2 3 /* * 開始點為第一個數* 1和2交換 ->2 1 3 * 1和3交換 ->3 2 1*/2 1 3 /** 從2 1 3遞歸* 開始點為第二個數* 1和3交換 ->2 3 1*/3 2 1 /** 從3 2 1遞歸* 開始點為第二個數* 2和1交換 ->3 1 2*//* 結果 */ 1 2 3 2 1 3 2 3 1 3 1 2 3 2 1

但是這種方法少了一種結果,{1 3 2} 。因為序列{1 2 3}的時候是以1為開始點,但是沒有對2和3進行交換。原因在于沒有從{1 2 3}遞歸并且開始點是第二個數的過程。所以,解決辦法就是當開始點進行交換時,也要和自己交換一次,但是交換的結果不能添加到結果中。但是這樣對于第一個序列{1 2 3}就不在結果中,所以需要在交換前手動添加第一個序列。
代碼如下

class Solution { public:vector<vector<int>> permute(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;/* 以idx位置作為開始點,依次和后面的交換 */for(int i = idx; i < nums.size(); ++i){/* 交換,獲取一個排列 */swap(nums[i], nums[idx]);/* 如果不是自己和自己交換,就把排列添加到結果中 */if(i != idx)res.push_back(nums);/* 遞歸調用,以下一個位置作為開始點 */get_permutation(nums, idx + 1, res);/* 交換完再換回來,回到開始的狀態,然后和下一個交換 */swap(nums[i], nums[idx]);}} };

擴展

Permutations II

原題鏈接Permutations II

和上面要求一樣,唯一區別是給定的序列可能有重復的元素
如果再按照上面的方法,那么會出現大量重復的結果,比如第一個1和第二個1交換,結果沒有變換,但是被添加了兩次。所以,在進行交換的時候,需要特別注意,以當前位置作為開始點和后面的元素進行交換時,這個元素在之前有沒有交換過,如果交換過了,就不用再交換了。
例如,如果開始時序列為{1 2 7 7 9},某次交換以2為開始點

/* swap(nums[1], nums[2]) -> 1 7 2 7 9 */ 開始點為第2個數22先和第一個7交換,變為1 7 2 7 9/* swap(nums[2], nums[3]) -> 1 7 7 2 9 */ 開始點變為第3個數7,7先和2交換,變為1 7 2 7 9/* ... */交換一輪后回到1 2 7 7 9 /* swap(nums[1], nums[3]) -> 1 7 7 2 9 */ 開始點為第2個數2,2和第二個7交換,變為1 7 7 2 9 此時已經和先前的結果重復了

原因就在于如果有重復的元素,那么開始點第一次和重復元素的第一個元素交換,接著和第二個元素交換獲取的排列,和開始點直接和重復元素的第二個元素交換獲取的排列是一樣的
所以,只需要和重復元素的第一個元素交換一次即可,后面重復的元素都不需要再次交換,因為在向后遞歸的過程中,開始點和后面的重復元素已經交換過了。

代碼如下

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-----获取无重复项/有重复项序列的全排列的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。