方法一:递归+回溯
全排列就是对数组元素交换位置,使每一种排列都可能出现。因为题目要求按照字典序排列输出,那毫无疑问第一个排列就是数组的升序排列,它的字典序最小,后续每个元素与它后面的元素交换一次位置就是一种排列情况,但是如果要保持原来的位置不变,那就不应该从它后面的元素开始交换而是从自己开始交换才能保证原来的位置不变,不会漏情况。
具体做法:
- step 1:先将数组排序,获取字典序最小的排列情况。
- step 2:递归的时候根据当前下标,遍历后续的元素,交换二者位置后,进入下一层递归。
- step 3:处理完一分支的递归后,将交换的情况再换回来进行回溯,进入其他分支。
- step 4:当前下标到达数组末尾就是一种排列情况。
该方法好像无法按照字典序输出?
时间复杂度:o(n*n!)
空间复杂度:o(n)
class Solution { public: void resort(vector<vector<int> >& res, vector<int>& num, int idx) { //到达最后一个元素输出 if (idx == num.size() - 1) { res.push_back(num); } else { for (int i = idx; i < num.size(); i++) { swap(num[i], num[idx]); resort(res, num, idx + 1); swap(num[i], num[idx]); } } } vector<vector<int> > permute(vector<int>& num) { vector<vector<int> > res; //先对数组进行排序 sort(num.begin(), num.end()); resort(res, num, 0); return res; } };
方法二:递归+dfs
将数组抽象为数,利用深度优先可以搜索得到所有的情况。
该方法可以按照字典序的顺序输出
时间复杂度:o(n*n!)
空间复杂度:o(n)
class Solution { public: void dfs(vector<int>& num, vector<bool>& flag, int idx) { if (idx == num.size()) { res.push_back(temp); } else { for (int i = 0; i < num.size(); i++) { if (flag[i] == false) { //数字未被选取时压入数组 flag[i] = true; temp.push_back(num[i]); dfs(num, flag, idx + 1); //回溯 temp.pop_back(); flag[i] = false; } } } } vector<vector<int> > permute(vector<int>& num) { //用来判断数字是否被选取 vector<bool> flag(num.size(), false); dfs(num, flag, 0); return res; } private: vector<int> temp; vector<vector<int> > res; };