给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
思路一:回溯
int* Source = NULL;
int Source_Size = 0;
int** Result = NULL;
int* Retcolsizes = NULL;
int Result_Index = 0;
int* Path = NULL;
int Path_Index = 0;
bool* Used = NULL;
//将回溯时用到的变量全部设置为全局变量,实现零传参,更加简洁;
int cmp(const void* a, const void* b){
return *(int*)a - *(int*)b;
}//C语言中排序函数qsort()用到的回调比较函数;
void Back_Track(){
if(Path_Index == Source_Size){
int* temi = (int*)malloc(sizeof(int) * Path_Index);
memcpy(temi, Path, sizeof(int) * Path_Index);
Result[Result_Index] = temi;
Retcolsizes[Result_Index] = Path_Index;
Result_Index++;
return;
}//递推终止条件:原数组中的所有元素均已被使用;
for(int i = 0; i < Source_Size; i++){
if(i && Source[i] == Source[i - 1] && !Used[i - 1]){
continue;
}
if(Used[i]){
continue;
}
//这两个剪枝条件使得对于排序后数组中的某一个连续的相同数字序列,每层的递推操作都只能选择连续相同数字序列的最左边的未被使用的第一个数字;
Path[Path_Index] = Source[i];
Path_Index++;
Used[i] = true;
Back_Track();
Used[i] = false;
Path_Index--;//正常的递推与回溯操作;
}
}
int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
Source = nums;
Source_Size = numsSize;
Result = (int**)malloc(sizeof(int*) * 630);
Retcolsizes = (int*)malloc(sizeof(int) * 630);
Result_Index = 0;
Path = (int*)malloc(sizeof(int) * numsSize);
Path_Index = 0;
Used = (bool*)malloc(sizeof(bool) * numsSize);
for(int i = 0; i < numsSize; i++){
Used[i] = false;
}
//全局变量初始化;
qsort(nums, numsSize, sizeof(int), cmp);//对数组进行排序;
Back_Track();
*returnSize = Result_Index;
*returnColumnSizes = Retcolsizes;
return Result;
//各返回值参数处理;
}
分析:
本题要求返回所有不重复的序列,想到可使用动态规划和回溯的方法进行作答。首先将结果和原来的数组用另一个数组来表示,遍历将不重复的序列放入结果数组中,同时将使用过的数放入used数组中,每次遍历的时候判断是否遇到重复数,若为重复数则跳过他们。遍历完后返回结果数组。
总结:
本题主要考察了动态规划和回溯问题的解决,对此问题要创建路径数组,结果数组等,判断是否由重复的数组,最后再输出不重复的数组