From 51405c06699acbb7e278d87a8f5429de28d80176 Mon Sep 17 00:00:00 2001 From: Yudong Jin Date: Tue, 17 Oct 2023 10:20:10 -0500 Subject: [PATCH] add permutations_ii.c and re-implement permutations_i.c (#868) --- codes/c/chapter_backtracking/CMakeLists.txt | 1 + codes/c/chapter_backtracking/permutations_i.c | 91 +++++++++---------- .../c/chapter_backtracking/permutations_ii.c | 81 +++++++++++++++++ 3 files changed, 126 insertions(+), 47 deletions(-) create mode 100644 codes/c/chapter_backtracking/permutations_ii.c diff --git a/codes/c/chapter_backtracking/CMakeLists.txt b/codes/c/chapter_backtracking/CMakeLists.txt index 8d768be3..70161b6d 100644 --- a/codes/c/chapter_backtracking/CMakeLists.txt +++ b/codes/c/chapter_backtracking/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(permutations_i permutations_i.c) +add_executable(permutations_ii permutations_ii.c) add_executable(preorder_traversal_i_compact preorder_traversal_i_compact.c) add_executable(preorder_traversal_ii_compact preorder_traversal_ii_compact.c) add_executable(preorder_traversal_iii_compact preorder_traversal_iii_compact.c) diff --git a/codes/c/chapter_backtracking/permutations_i.c b/codes/c/chapter_backtracking/permutations_i.c index 20d0a934..feb4b21d 100644 --- a/codes/c/chapter_backtracking/permutations_i.c +++ b/codes/c/chapter_backtracking/permutations_i.c @@ -1,82 +1,79 @@ /** * File: permutations_i.c * Created Time: 2023-06-04 - * Author: Gonglja (glj0@outlook.com) + * Author: Gonglja (glj0@outlook.com), Krahets (krahets@163.com) */ #include "../utils/common.h" +// 假设最多有 1000 个排列 +#define MAX_SIZE 1000 + /* 回溯算法:全排列 I */ -void backtrack(vector *state, vector *choices, vector *selected, vector *res) { +void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *selected, int **res, int *resSize) { // 当状态长度等于元素数量时,记录解 - if (state->size == choices->size) { - vector *newState = newVector(); - for (int i = 0; i < state->size; i++) { - vectorPushback(newState, state->data[i], sizeof(int)); + if (stateSize == choicesSize) { + res[*resSize] = (int *)malloc(choicesSize * sizeof(int)); + for (int i = 0; i < choicesSize; i++) { + res[*resSize][i] = state[i]; } - vectorPushback(res, newState, sizeof(vector)); + (*resSize)++; return; } // 遍历所有选择 - for (int i = 0; i < choices->size; i++) { - int *choice = malloc(sizeof(int)); - *choice = *((int *)(choices->data[i])); - // 剪枝:不允许重复选择元素 且 不允许重复选择相等元素 - bool select = *((bool *)(selected->data[i])); - if (!select) { + for (int i = 0; i < choicesSize; i++) { + int choice = choices[i]; + // 剪枝:不允许重复选择元素 + if (!selected[i]) { // 尝试:做出选择,更新状态 - *((bool *)selected->data[i]) = true; - vectorPushback(state, choice, sizeof(int)); + selected[i] = true; + state[stateSize] = choice; // 进行下一轮选择 - backtrack(state, choices, selected, res); + backtrack(state, stateSize + 1, choices, choicesSize, selected, res, resSize); // 回退:撤销选择,恢复到之前的状态 - *((bool *)selected->data[i]) = false; - vectorPopback(state); + selected[i] = false; } } } /* 全排列 I */ -vector *permutationsI(vector *nums) { - vector *iState = newVector(); - - int select[3] = {false, false, false}; - vector *bSelected = newVector(); - for (int i = 0; i < nums->size; i++) { - vectorPushback(bSelected, &select[i], sizeof(int)); +int **permutationsI(int *nums, int numsSize, int *returnSize) { + int *state = (int *)malloc(numsSize * sizeof(int)); + bool *selected = (bool *)malloc(numsSize * sizeof(bool)); + for (int i = 0; i < numsSize; i++) { + selected[i] = false; } + int **res = (int **)malloc(MAX_SIZE * sizeof(int *)); + *returnSize = 0; - vector *res = newVector(); + backtrack(state, 0, nums, numsSize, selected, res, returnSize); + + free(state); + free(selected); - // 前序遍历 - backtrack(iState, nums, bSelected, res); return res; } -/* 打印向量中的元素 */ -void printFunc(vector *v, void *p) { - int *node = p; - printf("%d", *node); -} - /* Driver Code */ int main() { int nums[] = {1, 2, 3}; - vector *iNums = newVector(); // int - for (int i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) { - vectorPushback(iNums, &nums[i], sizeof(int)); + int numsSize = sizeof(nums) / sizeof(nums[0]); + int returnSize; + + int **res = permutationsI(nums, numsSize, &returnSize); + + printf("输入数组 nums = "); + printArray(nums, numsSize); + printf("\n所有排列 res = \n"); + for (int i = 0; i < returnSize; i++) { + printArray(res[i], numsSize); } - vector *res = permutationsI(iNums); - - // 输出结果 - printf("输入数组 nums = "); - printArray(nums, sizeof(nums) / sizeof(nums[0])); - printf("所有排列 res = "); - printVectorMatrix(res, printFunc); - // 释放内存 - delVector(iNums); - delVector(res); + for (int i = 0; i < returnSize; i++) { + free(res[i]); + } + free(res); + return 0; } diff --git a/codes/c/chapter_backtracking/permutations_ii.c b/codes/c/chapter_backtracking/permutations_ii.c new file mode 100644 index 00000000..a5ba6d60 --- /dev/null +++ b/codes/c/chapter_backtracking/permutations_ii.c @@ -0,0 +1,81 @@ +/** + * File: permutations_ii.c + * Created Time: 2023-10-17 + * Author: Krahets (krahets@163.com) + */ + +#include "../utils/common.h" + +// 假设最多有 1000 个排列,元素最大为 1000 +#define MAX_SIZE 1000 + +/* 回溯算法:全排列 II */ +void backtrack(int *state, int stateSize, int *choices, int choicesSize, bool *selected, int **res, int *resSize) { + // 当状态长度等于元素数量时,记录解 + if (stateSize == choicesSize) { + res[*resSize] = (int *)malloc(choicesSize * sizeof(int)); + for (int i = 0; i < choicesSize; i++) { + res[*resSize][i] = state[i]; + } + (*resSize)++; + return; + } + // 遍历所有选择 + bool duplicated[MAX_SIZE] = {false}; + for (int i = 0; i < choicesSize; i++) { + int choice = choices[i]; + // 剪枝:不允许重复选择元素 且 不允许重复选择相等元素 + if (!selected[i] && !duplicated[choice]) { + // 尝试:做出选择,更新状态 + duplicated[choice] = true; // 记录选择过的元素值 + selected[i] = true; + state[stateSize] = choice; + // 进行下一轮选择 + backtrack(state, stateSize + 1, choices, choicesSize, selected, res, resSize); + // 回退:撤销选择,恢复到之前的状态 + selected[i] = false; + } + } +} + +/* 全排列 II */ +int **permutationsII(int *nums, int numsSize, int *returnSize) { + int *state = (int *)malloc(numsSize * sizeof(int)); + bool *selected = (bool *)malloc(numsSize * sizeof(bool)); + for (int i = 0; i < numsSize; i++) { + selected[i] = false; + } + int **res = (int **)malloc(MAX_SIZE * sizeof(int *)); + *returnSize = 0; + + backtrack(state, 0, nums, numsSize, selected, res, returnSize); + + free(state); + free(selected); + + return res; +} + +/* Driver Code */ +int main() { + int nums[] = {1, 1, 2}; + int numsSize = sizeof(nums) / sizeof(nums[0]); + int returnSize; + + int **res = permutationsII(nums, numsSize, &returnSize); + + printf("输入数组 nums = "); + printArray(nums, numsSize); + printf("\n所有排列 res = \n"); + for (int i = 0; i < returnSize; i++) { + printArray(res[i], numsSize); + } + + // 释放内存 + for (int i = 0; i < returnSize; i++) { + free(res[i]); + } + free(res); + + return 0; +}