简单来说,全排列是指不同元素在不同位置上的所有方案。这是「组合数学」的相关知识。
C++ 提供了独有的 next_permutation() 函数,它在原数组上改变元素排列顺序。
例题 1:力扣 31. 下一个排列
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列(即,组合出下一个更大的整数)。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
参考代码
class Solution {public:void nextPermutation(vector<int>& nums) {/* 代码实现:int i = nums.size() - 2;while (i >= 0 && nums[i] >= nums[i+1]) i--;if (i >= 0) {int j = nums.size() - 1;while (j >= i && nums[j] <= nums[i]) j--;swap(nums[i], nums[j]);}reverse(nums.begin() + i + 1, nums.end());*/// 函数实现next_permutation(nums.begin(), nums.end());}};
例题 2:蓝桥 带分数【第四届】【省赛】
这个问题可以看成,数字 1 ~ 9 的所有排列顺序上,枚举两个分割点,得到三个数,验证这三个数是否符合等式。next_permutation() 函数仅在遍历到最后一个排列时返回 false ,配合 do_while 语句可以从第一个排列开始,遍历所有的排列。
参考代码
#include <iostream>
#include <algorithm>
using namespace std;
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int n = 9;
int x;
// 取得 a[] 上下标 [l, r] 组成的数字
int getNum(int l, int r) {
int ret = 0;
for (int i=l; i<r; ++i) {
ret *= 10;
ret += a[i];
}
return ret;
}
// 检查是否使等式成立
bool check(int i, int j) {
int a = getNum(0, i);
int b = getNum(i, j);
int c = getNum(j, n);
return b % c == 0 && x == a + b / c;
}
int main() {
cin >> x;
int ans = 0;
// 遍历所有排列
do {
// 两重 for 枚举两个分割点
for (int i=1; i<n-1; ++i) {
for (int j=i+1; j<n; ++j) {
ans += check(i, j); // 统计成立的等式数量
}
}
} while (next_permutation(a, a + n));
cout << ans << endl;
return 0;
}
你也可以使用 dfs 搜索所有的排列。可是既然有 next_permutation(),为什么不呢。
DFS 实现参考:AcWing 1209. 带分数
