给定四个不同的数字(0-9),我们需要生成所有可能的三位数组合,要求:
例如输入1 2 3 4,输出应为从123到432的所有24种排列。
解决这个问题主要有两种思路:
暴力枚举法的优势在于:
标准库排列法的优势在于:
提示:教学场景建议先掌握暴力枚举法,实际项目开发推荐使用标准库函数
c复制#include <stdio.h>
void composeNumber(int a, int b, int c, int d) {
int num[4] = {a, b, c, d};
for(int i = 0; i < 4; i++) { // 百位选择
for(int j = 0; j < 4; j++) { // 十位选择
if(j == i) continue; // 避免数字重复
for(int k = 0; k < 4; k++) { // 个位选择
if(k == i || k == j) continue;
printf("%d\n", num[i]*100 + num[j]*10 + num[k]);
}
}
}
}
int main() {
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
composeNumber(a, b, c, d);
return 0;
}
continue跳过使用相同数字的情况百位×100 + 十位×10 + 个位变量未重置:
c复制// 错误示例
int sum = 0;
for(...) {
sum = num[i]*100;
// 忘记在每次循环开始时重置sum
}
索引混淆:
c复制// 错误示例
if(k == i || k == i) continue; // 第二个条件应为k == j
输出格式错误:
c复制// 错误示例
printf("%d", num[i], num[j], num[k]); // 缺少数值计算
调试技巧:可在每个循环开始处添加printf打印当前变量值,观察执行流程
cpp复制#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int nums[4];
for(int i=0; i<4; i++) cin >> nums[i];
sort(nums, nums+4); // 必须先排序
do {
cout << nums[0] << nums[1] << nums[2] << endl;
} while(next_permutation(nums, nums+4));
return 0;
}
| 方法 | 代码行数 | 时间复杂度 | 可读性 | 扩展性 |
|---|---|---|---|---|
| C语言三重循环 | 20 | O(n³) | 中等 | 强 |
| C++ next_permutation | 10 | O(n!) | 高 | 弱 |
cpp复制template<typename T>
void printPermutations(T arr[], int n, int k) {
sort(arr, arr+n);
do {
for(int i=0; i<k; i++) cout << arr[i] << " ";
cout << endl;
} while(next_permutation(arr, arr+n));
}
当输入数字有重复时,需要修改算法:
cpp复制sort(nums, nums+4);
do {
// 检查前三位是否有重复
if(nums[0]==nums[1] || nums[1]==nums[2]) continue;
cout << nums[0] << nums[1] << nums[2] << endl;
} while(next_permutation(nums, nums+4));
对于4个不同数字取3个的排列数计算:
P(4,3) = 4! / (4-3)! = 24种
排列数公式:
P(n,k) = n! / (n-k)!
输入验证:
cpp复制if(a==b || a==c || a==d || b==c || b==d || c==d) {
cerr << "输入数字必须互不相同" << endl;
return 1;
}
性能优化:
输出格式化:
cpp复制cout << setw(3) << setfill('0') << nums[0]*100+nums[1]*10+nums[2];
单元测试用例:
cpp复制void test() {
// 边界测试
assert(permutationCount(1,2,3,4) == 24);
// 含0测试
assert(permutationCount(0,1,2,3) == 18); // 0不能作为百位数
}
在实际项目中遇到类似排列组合问题时,建议先明确具体需求:是否需要所有排列、是否有重复元素、是否需要考虑顺序等。根据不同的需求场景选择合适的算法实现,平衡代码可读性和运行效率。