题目描述:
给定一个没有重复数字的序列,返回其所有可能的全排列。
输入输出示例:
输入:
[1,2,3]
输出:
[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
对于该题有两种解题方法:回溯法 和 库函数法
解法一:回溯法
回溯法:是一种通过探索所有的候选解来找出所有的解的算法。如果该候选解确认不是一个解时,回溯算法会抛弃该解并且回退到上一步,重新求解;
回溯法特点:会遍历所有解;求解下一步之前必须保存上一步的解,保证可以回退;
回溯法的解题思路:
先固定一位,假设先固定第一个位置为1,然后第二位可以为2,那么第三位只能是3;(回退)然后可以把第二位变成3,第三位就只能是2了。
当第一个位置为2,然后第二位可以为1,那么第三位只能是3;(回退)然后可以把第二位变成3,那么第三位只能是1了。
同理,将第一位定为3…。
通过上述方法,将该方法形象化可以得到一棵树:
该树可以称之为:决策树。该树上每一条从根节点到叶子节点的路径就是一个解;
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
BackTrack(res, nums, nums.size(), 0);
return res;
}
void BackTrack(vector<vector<int>>& res, vector<int>& nums, const int& size, int level)
{
//确定最后一个元素后,将结果保存到结果集中
if (level == size)
{
res.push_back(nums);
return;
}
for (int i = level; i < size; ++i)
{
if (i != level)
swap(nums[i], nums[level]);
BackTrack(res, nums, size, level + 1);
if (i != level)//回溯
swap(nums[i], nums[level]);
}
}
};
解法二:库函数法
库函数法相对于回溯法来说,比较简单,只需要简单调用库函数 next_permutation() 即可.
函数原型:
头文件:
#include< algorithm >
bool next_permutation (BidirectionalIterator first, BidirectionalIterator last );
返回值:
如果函数可以将对象重新排列成词典更大的排列,则为true。否则,函数返回false以指示排列不大于上一个排列,而是尽可能低的排列(按升序排序)。
函数原理:
在当前序列中,从尾端往前寻找两个相邻元素,前一个记为i,后一个记为ii,并且满足i < ii。然后再从尾端寻找另一个元素j,如果满足i < *j,即将第i个元素与第j个元素对调,并将第ii个元素之后(包括ii)的所有元素颠倒排序,即求出下一个序列了。
使用该库函数有一个注意点:要全排列的数组开始必须是按照升序排列的;
class Solution {
public:
vector<vector<int>> permute(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
do{
res.push_back(nums);
}while(next_permutation(nums.begin(),nums.end()));
return res;
}
};
题目链接:https://leetcode-cn.com/problems/permutations/