代码随想录第二十五天(一刷&&C语言)|递增子序列&&全排列&&全排列II

创作目的:为了方便自己后续复习重点,以及养成写博客的习惯。

组合和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果

一、递增子序列

思路:参考carl文档

        已经是递增序列故而不用排序,元素不能重复使用,需要startIndex,调整下一层递归的起始位置。在遍历树形结构找每一个节点,可以通过startIndex结束递归,可以不加终止条件。通过树形结构了解到,同一层元素使用过就不能再使用了。

ledcode题目:https://leetcode.cn/problems/non-decreasing-subsequences/

AC代码:

int* path;
int pathTop;
int** ans;
int ansTop;
int* length;
//将当前path中的内容复制到ans中
void copy() {
    int* tempPath = (int*)malloc(sizeof(int) * pathTop);
    memcpy(tempPath, path, pathTop * sizeof(int));
    length[ansTop] = pathTop;
    ans[ansTop++] = tempPath;
}

//查找uset中是否存在值为key的元素
int find(int* uset, int usetSize, int key) {
    int i;
    for(i = 0; i < usetSize; i++) {
        if(uset[i] == key)
            return 1;
    }
    return 0;
}

void backTracking(int* nums, int numsSize, int startIndex) {
    //当path中元素大于1个时,将path拷贝到ans中
    if(pathTop > 1) {
        copy();
    }
    int* uset = (int*)malloc(sizeof(int) * numsSize);
    int usetTop = 0;
    int i;
    for(i = startIndex; i < numsSize; i++) {
        //若当前元素小于path中最后一位元素 || 在树的同一层找到了相同的元素,则continue
        if((pathTop > 0 && nums[i] < path[pathTop - 1]) || find(uset, usetTop, nums[i]))
            continue;
        //将当前元素放入uset
        uset[usetTop++] = nums[i];
        //将当前元素放入path
        path[pathTop++] = nums[i];
        backTracking(nums, numsSize, i + 1);
        //回溯
        pathTop--;
    }
}

int** findSubsequences(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    //辅助数组初始化
    path = (int*)malloc(sizeof(int) * numsSize);
    ans = (int**)malloc(sizeof(int*) * 33000);
    length = (int*)malloc(sizeof(int*) * 33000);
    pathTop = ansTop = 0;

    backTracking(nums, numsSize, 0);

    //设置数组中返回元素个数,以及每个一维数组的长度
    *returnSize = ansTop;
    *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
    int i;
    for(i = 0; i < ansTop; i++) {
        (*returnColumnSizes)[i] = length[i];
    }
    return ans;
}

二、全排列

思路:参考carl文档

        处理排列问题就不需要使用startIndex而是需要一个used数组,标记已经选元素。当收集元素的数组path的大小和nums数组一样大时,说明找到了一个全排列,也表示到达了叶子节点。排列问题每次都要从头开始搜索,used数组就是记录path里有哪些元素使用了,一个排列里一个元素只能使用一次。

lecode题目:https://leetcode.cn/problems/permutations/

AC代码:

int* path;
int pathTop;
int** ans;
int ansTop;

//将used中元素都设置为0
void initialize(int* used, int usedLength) {
    int i;
    for(i = 0; i < usedLength; i++) {
        used[i] = 0;
    }
}

//将path中元素拷贝到ans中
void copy() {
    int* tempPath = (int*)malloc(sizeof(int) * pathTop);
    int i;
    for(i = 0; i < pathTop; i++) {
        tempPath[i] = path[i];
    }
    ans[ansTop++] = tempPath;
}

void backTracking(int* nums, int numsSize, int* used) {
    //若path中元素个数等于nums元素个数,将nums放入ans中
    if(pathTop == numsSize) {
        copy();
        return;
    }
    int i;
    for(i = 0; i < numsSize; i++) {
        //若当前下标中元素已使用过,则跳过当前元素
        if(used[i])
            continue;
        used[i] = 1;
        path[pathTop++] = nums[i];
        backTracking(nums, numsSize, used);
        //回溯
        pathTop--;
        used[i] = 0;
    }
}

int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    //初始化辅助变量
    path = (int*)malloc(sizeof(int) * numsSize);
    ans = (int**)malloc(sizeof(int*) * 1000);
    int* used = (int*)malloc(sizeof(int) * numsSize);
    //将used数组中元素都置0
    initialize(used, numsSize);
    ansTop = pathTop = 0;

    backTracking(nums, numsSize, used);

    //设置path和ans数组的长度
    *returnSize = ansTop;
    *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
    int i;
    for(i = 0; i < ansTop; i++) {
        (*returnColumnSizes)[i] = numsSize;
    }
    return ans;
}

三、全排列II

思路:参考carl文档

         与全排列的区别在于给定一个可重复数字的序列,要返回所有不重复的全排列(去重)。而且去重一定要对元素进行排序,通过相邻的节点来判断元素是否重复使用了。     同一树层的前一位(nums[i-1])如果使用过,那么就进行去重。

ledcode题目:https://leetcode.cn/problems/permutations-ii/description/

AC代码:

//临时数组
int *path;
//返回数组
int **ans;
int *used;
int pathTop, ansTop;

//拷贝path到ans中
void copyPath() {
    int *tempPath = (int*)malloc(sizeof(int) * pathTop);
    int i;
    for(i = 0; i < pathTop; ++i) {
        tempPath[i] = path[i];
    }
    ans[ansTop++] = tempPath;
}

void backTracking(int* used, int *nums, int numsSize) {
    //若path中元素个数等于numsSize,将path拷贝入ans数组中
    if(pathTop == numsSize)
        copyPath();
    int i;
    for(i = 0; i < numsSize; i++) {
        //若当前元素已被使用
        //或前一位元素与当前元素值相同但并未被使用
        //则跳过此分支
        if(used[i] || (i != 0 && nums[i] == nums[i-1] && used[i-1] == 0))
            continue;

        //将当前元素的使用情况设为True
        used[i] = 1;
        path[pathTop++] = nums[i];
        backTracking(used, nums, numsSize);
        used[i] = 0;
        --pathTop;
    }
}

int cmp(void* elem1, void* elem2) {
    return *((int*)elem1) - *((int*)elem2);
}

int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
    //排序数组
    qsort(nums, numsSize, sizeof(int), cmp);
    //初始化辅助变量
    pathTop = ansTop = 0;
    path = (int*)malloc(sizeof(int) * numsSize);
    ans = (int**)malloc(sizeof(int*) * 1000);
    //初始化used辅助数组
    used = (int*)malloc(sizeof(int) * numsSize);
    int i;
    for(i = 0; i < numsSize; i++) {
        used[i] = 0;
    }

    backTracking(used, nums, numsSize);

    //设置返回的数组的长度
    *returnSize = ansTop;
    *returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
    int z;
    for(z = 0; z < ansTop; z++) {
        (*returnColumnSizes)[z] = numsSize;
    }
    return ans;
}

全篇后记:

        在明确思路的前提下,才能开始做,不然总会去走回头路。

最近更新

  1. TCP协议是安全的吗?

    2023-12-06 14:44:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-06 14:44:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-06 14:44:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-06 14:44:05       20 阅读

热门阅读

  1. IDC网络设备监控脚本-FLOW流监控

    2023-12-06 14:44:05       28 阅读
  2. 代码随想录二刷 |队列与栈 |有效的括号

    2023-12-06 14:44:05       43 阅读
  3. ubuntu重启后下无wifi,蓝牙和飞行模式切换问题

    2023-12-06 14:44:05       40 阅读
  4. github可访问但无法clone问题

    2023-12-06 14:44:05       35 阅读
  5. Linux计算机系统参数获取和压力测试

    2023-12-06 14:44:05       38 阅读
  6. Ubuntu22.04LTS配置rsync服务

    2023-12-06 14:44:05       44 阅读
  7. [cmake] --- find_package

    2023-12-06 14:44:05       28 阅读
  8. 如何关闭vue项目中的[eslint]校验

    2023-12-06 14:44:05       40 阅读
  9. CSS外边距重叠:原理、结果

    2023-12-06 14:44:05       29 阅读
  10. LeetCode1005. Maximize Sum Of Array After K Negations

    2023-12-06 14:44:05       23 阅读
  11. vue打包完成后出现空白页原因及解决

    2023-12-06 14:44:05       42 阅读