题目:输入一个字符串,打印出该字符串中字符的所有排列。
全排列问题,且各个字符都不相同。
代码:
void Permutation(char *pStr)
{
if (pStr == nullptr)
return;
Permutation(pStr, pStr);
}
void Permutation(char *pStr, char *pBegin)
{
if (*pBegin == '\0')
printf("%s\n", pStr);
for (char *pCh = pBegin; *pCh != '\0'; pCh++)
{
swap(*pCh, *pBegin);
Permutation(pStr, pBegin + 1);
swap(*pCh, *pBegin);
}
}
复杂度分析:
时间复杂度:O(n × n!),其中 n 是序列的长度。回溯的调用次数是 O(n!),对于每个回溯的叶子节点,我们需要将当前答案使用 O(n) 的时间复制到答案数组中,相乘得时间复杂度为 O(n × n!)。
空间复杂度:O(n),其中 n 是序列的长度。除答案数组以外,递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,这里可知递归调用深度为 O(n)。
题目来源:LeetCode 46. 全排列
给定一个没有重复数字的序列,返回其所有可能的全排列。
代码:
/*
* @lc app=leetcode.cn id=46 lang=cpp
*
* [46] 全排列
*/
// @lc code=start
class Solution
{
public:
// 主函数
vector<vector<int>> permute(vector<int> &nums)
{
vector<vector<int>> ans;
backtrack(nums, 0, ans);
return ans;
}
// 辅函数
void backtrack(vector<int> &nums, int level, vector<vector<int>> &ans)
{
if (level == nums.size() - 1)
{
ans.push_back(nums);
return;
}
for (int i = level; i < nums.size(); i++)
{
swap(nums[i], nums[level]); // 修改当前节点状态
backtrack(nums, level + 1, ans); // 递归子节点
swap(nums[i], nums[level]); // 回改当前节点状态
}
}
};
// @lc code=end
复杂度分析:
时间复杂度:O(n × n!),其中 n 是数组 nums 的长度。回溯的调用次数是 O(n!),对于每个回溯的叶子节点,我们需要将当前答案使用 O(n) 的时间复制到答案数组中,相乘得时间复杂度为 O(n × n!)。
空间复杂度:O(n),其中 n 是数组 nums 的长度。除答案数组以外,递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,这里可知递归调用深度为 O(n)。
题目来源:LeetCode 47. 全排列 II
序列中有重复的数字,要考虑重复,需要剪枝。
代码:
/*
* @lc app=leetcode.cn id=47 lang=cpp
*
* [47] 全排列 II
*/
// @lc code=start
class Solution
{
private:
vector<bool> visited;
public:
// 主函数
vector<vector<int>> permuteUnique(vector<int> &nums)
{
vector<vector<int>> ans;
vector<int> seq;
visited = vector<bool>(nums.size(), false);
sort(nums.begin(), nums.end());
backtrack(nums, 0, ans, seq);
return ans;
}
// 辅函数
void backtrack(vector<int> &nums, int level, vector<vector<int>> &ans, vector<int> &seq)
{
if (level == nums.size())
{
ans.emplace_back(seq);
return;
}
for (size_t i = 0; i < nums.size(); i++)
{
if (visited[i] || (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]))
{
continue;
}
seq.emplace_back(nums[i]);
visited[i] = true;
backtrack(nums, level + 1, ans, seq);
visited[i] = false;
seq.pop_back();
}
}
};
// @lc code=end
复杂度分析:
时间复杂度:O(n × n!),其中 n 是数组 nums 的长度。回溯的调用次数是 O(n!),对于每个回溯的叶子节点,我们需要将当前答案使用 O(n) 的时间复制到答案数组中,相乘得时间复杂度为 O(n × n!)。
空间复杂度:O(n),其中 n 是数组 nums 的长度。我们需要 O(n) 的标记数组,同时在递归的时候栈深度会达到 O(n),因此总空间复杂度为 O(n+n)=O(2n)=O(n)。