# 排列问题 排列问题:N 个数按一定规则全排列,有几种排列方式 ## [46. 全排列](https://leetcode.cn/problems/permutations/) ## [47. 全排列 II](https://leetcode.cn/problems/permutations-ii/) 和 s0046 相比就加了去重。有两种去重思路,一个是用哈希表记录每一层的使用情况,另一种是排序 + 判断,后者性能更好所以优先选择后者。 哈希表法: ```cpp #include "s0047_permutations_ii.hpp" void permuteUniqueDFS(vector &path, vector> &result, vector &used, vector &nums) { int len = nums.size(); // 终止条件 if (path.size() == len) { result.push_back(path); return; } // 创建一个哈希表用来记录当前层中使用过的元素 unordered_map map; // 开始迭代 for (int i{0}; i < len; ++i) { // 如果当前元素在树枝或树层使用过,则跳过 if (used[i] || map.count(nums[i]) == 1) continue; // 否则处理当前节点 map[nums[i]] = true; path.push_back(nums[i]); used[i] = true; permuteUniqueDFS(path, result, used, nums); used[i] = false; path.pop_back(); } } vector> S0047::permuteUnique(vector &nums) { vector path{}; vector> result{}; vector used(nums.size(), false); permuteUniqueDFS(path, result, used, nums); return result; } ``` 排序 + 判断: ```cpp void permuteUniqueDFS(vector &path, vector> &result, vector &used, vector &nums, int startIndex) { int len = nums.size(); // 终止条件 if (path.size() == len) { result.push_back(path); return; } // 开始迭代 for (int i{0}; i < len; ++i) { // 如果当前元素在树层使用过,则跳过 if (used[i] || (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)) continue; // 否则处理当前节点 path.push_back(nums[i]); used[i] = true; permuteUniqueDFS(path, result, used, nums, i + 1); used[i] = false; path.pop_back(); } } vector> S0047::permuteUnique(vector &nums) { vector path{}; vector> result{}; vector used(nums.size(), false); sort(nums.begin(), nums.end()); permuteUniqueDFS(path, result, used, nums, 0); return result; } ``` ## [332. 重新安排行程](https://leetcode.cn/problems/reconstruct-itinerary/) 这道题本来是想不到回溯法的,但是如果某道题能够拆分成多个步骤,每个步骤都在前一步的基础上进行选择,那么就可以用回溯法。 ![demo](https://paste.sainnhe.dev/ej8H.png)