全排列(Permutation)是数学中一个经典的问题,指的是从一组元素中,将所有元素按任意顺序排列形成的所有可能序列。
输入条件:
[1, 2, 3]
的全排列。输出结果:
输出所有元素的排列组合。
例如:[1, 2, 3]
的全排列是:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
数量公式:
n
个互异元素,其全排列数量为 (阶乘)。
n = 3
时,全排列数量为 。
通过递归交换或回溯实现:
#include <iostream>
#include <vector>
using namespace std;
void backtrack(vector<int>& nums, int start, vector<vector<int>>& result) {
if (start == nums.size()) {
result.push_back(nums);
return;
}
for (int i = start; i < nums.size(); i++) {
swap(nums[start], nums[i]); // 交换当前元素
backtrack(nums, start + 1, result); // 递归处理子问题
swap(nums[start], nums[i]); // 撤销交换(回溯)
}
}
int main() {
vector<int> nums = {1, 2, 3};
vector<vector<int>> result;
backtrack(nums, 0, result);
for (const auto& perm : result) {
for (int num : perm) {
cout << num << " ";
}
cout << endl;
}
return 0;
}
C++ 提供了 std::next_permutation
,可以简单地生成字典序全排列:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> nums = {1, 2, 3};
do {
for (int num : nums) {
cout << num << " ";
}
cout << endl;
} while (next_permutation(nums.begin(), nums.end())); // 调用 STL 函数
return 0;
}
增长较快,可能需要改用启发式算法。
全排列是基础的数学与算法问题,其思想在递归、动态规划和搜索算法中广泛应用!
题目链接:全排列 题目概述:
解题思路:递归流程如下:
class Solution {
vector<vector<int>> it;
vector<int> path;
bool check[7];//check用来存储是否被使用过
public:
void dfs(vector<int>& nums, vector<int>& path) {
if (path.size() == nums.size()) {
it.push_back(path);
}
else {
for (int a = 0; a < nums.size(); a++) {
if (!check[a]) {
path.push_back(nums[a]);
check[a] = true;//标记,下次不能再选
dfs(nums, path);
check[a] = false;//回溯复原
path.pop_back();
}
}
}
}
vector<vector<int>> permute(vector<int>& nums)
{
dfs(nums, path);
return it;
}
};
题目链接:子集 题目介绍:
解题思路:
class Solution {
public:
vector<vector<int>> ret;
vector<int> path;
void dfs(vector<int>& nums, int pos) {
if (pos == nums.size()) {
ret.push_back(path);
return;
}
// 选
path.push_back(nums[pos]);
dfs(nums, pos + 1);
path.pop_back(); // 恢复现场
// 不选
dfs(nums, pos + 1);
}
vector<vector<int>> subsets(vector<int>& nums) {
dfs(nums, 0);
return ret;
}
};
题目链接:全排列 题目介绍:
解题思路: 因此,我们需 要对相同元素定义⼀种规则,使得其组成的排列不会形成重复的情况:
class Solution {
vector<int> path;
vector<vector<int>> ret;
bool check[9];
public:
vector<vector<int>> permuteUnique(vector<int>& nums) {
sort(nums.begin(), nums.end());//先进行排序
dfs(nums);
return ret;
}
void dfs(vector<int>& nums) {
if (path.size() == nums.size()) {
ret.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
// 剪枝
if (check[i] == false &&(i == 0 || nums[i] != nums[i - 1] || check[i - 1] != false))//非常的巧妙,想要插入必须满足以下要求 1.没有被插入过 2.第一位(没有前一项)||当前项和其前一项不一样||前一项已经被插入过了
{
path.push_back(nums[i]);
check[i] = true;
dfs(nums);
path.pop_back(); // 恢复现场
check[i] = false;
}
}
}
};
题目链接:括号生成 题目介绍:
解题思路: 从左往右进⾏递归,在每个位置判断放置左右括号的可能性,若此时放置左括号合理,则放置左括号 继续进⾏递归,右括号同理。 ⼀种判断括号是否合法的⽅法:从左往右遍历,左括号的数量始终⼤于等于右括号的数量,并且左括 号的总数量与右括号的总数量相等。因此我们在递归时需要进⾏以下判断:
class Solution {
public:
vector<string> str;
void dfs(string it, int left,int right)
{
if(left==0)//做括号全部用完
{
while(right)
{
it.push_back(')');
right--;
}
str.push_back(it);
return;
}
it.push_back('(');//插入左括号
dfs(it,left-1,right);
it.pop_back();//回溯,回复现场
if(right>left)//右括号剩余必须比左括号多
{
it.push_back(')');
dfs(it,left,right-1);
it.pop_back();//回溯
}
}
vector<string> generateParenthesis(int n) {
string it;
int left=n;
int right=n;
it.push_back('(');//左边先插入一个(,避免第一个就是)的错误
left--;
dfs(it,left,right);
return str;
}
};
题目链接:组合 题目介绍:
题⽬要求我们从1到n中选择k个数的所有组合,其中不考虑顺序。也就是说,[1,2]和[2,1]等价。我 们需要找出所有的组合,但不能重复计算相同元素的不同顺序的组合。对于选择组合,我们需要进⾏ 如下流程:
class Solution {
public:
bool check[20];
vector<vector<int>> it;
vector<int> flag;
void dfs(int n, int k, int first) {
if (k)
{
for (int i = first; i <= n; i++)
{
flag.push_back(i);
dfs(n, k-1,i+1);
flag.pop_back();
}
}
else
{
it.push_back(flag);
}
}
vector<vector<int>> combine(int n, int k) {
dfs(n, k, 1);
return it;
}
};