首页 > 编程语言 >代码随想录算法训练营第二十四天|Day24 回溯算法

代码随想录算法训练营第二十四天|Day24 回溯算法

时间:2024-10-23 23:18:42浏览次数:3  
标签:numsSize returnSize int Day24 nums 随想录 算法 result path

93.复原IP地址

题目链接/文章讲解:https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%B0%E5%9D%80.html

视频讲解:https://www.bilibili.com/video/BV1XP4y1U73i/

思路

char** result;
int resultTop;
int segments[3];
int isValid(char* s, int start, int end) {
    if(start > end)
        return 0;
    if (s[start] == '0' && start != end) { 
                return false;
    }
    int num = 0;
    for (int i = start; i <= end; i++) {
        if (s[i] > '9' || s[i] < '0') { 
            return false;
        }
        num = num * 10 + (s[i] - '0');
        if (num > 255) { 
            return false;
        }
    }
    return true;
}
void backTracking(char* s, int startIndex, int pointNum) {
    if(pointNum == 3) {
        if(isValid(s, startIndex, strlen(s) - 1)) {
            char* tempString = (char*)malloc(sizeof(char) * strlen(s) + 4);
            int j;
            int count = 0;
            int count1 = 0;
            for(j = 0; j < strlen(s); j++) {
                tempString[count++] = s[j];
                if(count1 < 3 && j == segments[count1]) {
                    tempString[count++] = '.';
                    count1++;
                }
            }
            tempString[count] = 0;
            result = (char**)realloc(result, sizeof(char*) * (resultTop + 1));
            result[resultTop++] = tempString;
        }
        return ;
    }
    int i;
    for(i = startIndex; i < strlen(s); i++) {
        if(isValid(s, startIndex, i)) {
            segments[pointNum] = i;
            backTracking(s, i + 1, pointNum + 1);
        }
        else {
            break;
        }
    }
}
char ** restoreIpAddresses(char * s, int* returnSize){
    result = (char**)malloc(0);
    resultTop = 0;
    backTracking(s, 0, 0);
    *returnSize = resultTop;
    return result;
}

学习反思

使用回溯算法解决了将字符串s分割为IP地址的问题。代码中的函数isValid用于判断分割出的子串是否是合法的IP地址的一部分。函数backTracking用于递归地生成所有可能的IP地址分割方案。

  1. 代码中使用了全局变量resultresultTop作为存储结果的数组和数组大小。在需要扩容数组时,使用了realloc函数进行动态内存分配。虽然这种做法是合法的,但不推荐使用全局变量,因为全局变量的使用会增加代码的不确定性和难以维护性。

  2. 在递归函数backTracking中,使用了一个额外的数组segments来记录应该加入.的位置。这样可以避免在生成最终的IP地址字符串时的复杂操作。同时,也使用了两个计数器countcount1来分别记录字符串的下标和.的数量。

  3. 在递归函数backTracking中,使用了两层循环。外层循环用于遍历从startIndex到字符串的末尾的所有可能的起始位置,内层循环用于判断从startIndex到当前位置的子串是否是合法的IP地址的一部分。在内层循环中,如果遇到不合法的子串,则退出内层循环,进入下一轮外层循环。

78.子集

题目链接/文章讲解:https://programmercarl.com/0078.%E5%AD%90%E9%9B%86.html

视频讲解:https://www.bilibili.com/video/BV1U84y1q7Ci

思路

void backtrack(int* nums, int numsSize, int startIndex, int** result, int* returnSize, int* returnColumnSizes, int* path, int pathSize) {
    result[*returnSize] = malloc(pathSize * sizeof(int)); 
    for (int i = 0; i < pathSize; i++) {
        result[*returnSize][i] = path[i];
    }
    returnColumnSizes[*returnSize] = pathSize; 
    (*returnSize)++; 
    for (int i = startIndex; i < numsSize; i++){
        path[pathSize] = nums[i];
        backtrack(nums, numsSize, i + 1, result, returnSize, returnColumnSizes, path, pathSize + 1);
    }
}
int** subsets(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    *returnSize = 0;
    int** result = malloc(1024 * sizeof(int*)); 
    *returnColumnSizes = malloc(1024 * sizeof(int)); 
    int* path = malloc(numsSize * sizeof(int)); 
    backtrack(nums, numsSize, 0, result, returnSize, *returnColumnSizes, path, 0);
    free(path);
    
    return result;
}

学习反思

实现了生成一个数组的所有子集的功能。使用回溯算法解决了这个问题。代码中的函数backtrack用于递归地生成所有子集,函数subsets是一个包装函数,用于初始化一些变量,并调用backtrack函数。

  1. backtrack函数中,首先将当前路径添加到结果中。为当前子集分配内存并将路径的元素复制到当前子集中。然后记录当前子集的大小,并递增结果的计数。这样可以将当前子集添加到结果数组中。

  2. 在递归函数backtrack中,使用了两层循环。外层循环用于遍历从startIndex到数组的末尾的所有可能的起始位置,内层循环用于构建子集。在内层循环中,将当前数字添加到路径中,然后递归调用自身,继续构建子集。

  3. 在主函数subsets中,首先初始化一些变量,包括结果数组、每个子集的大小数组和当前路径数组。然后调用backtrack函数,开始回溯过程。

90.子集II

题目链接/文章讲解:https://programmercarl.com/0090.%E5%AD%90%E9%9B%86II.html

视频讲解:https://www.bilibili.com/video/BV1vm4y1F71J

思路

int compare(const void* a, const void* b) {
    return (*(int*)a - *(int*)b);
}

void backtrack(int* nums, int numsSize, int startIndex, int** result, int* returnSize, int* returnColumnSizes, int* path, int pathSize) {
    result[*returnSize] = malloc(pathSize * sizeof(int)); 
    for (int i = 0; i < pathSize; i++) {
        result[*returnSize][i] = path[i];
    }
    returnColumnSizes[*returnSize] = pathSize; 
    (*returnSize)++;
    for (int i = startIndex; i < numsSize; i++) {
        if (i > startIndex && nums[i] == nums[i - 1]) {
            continue;
        }
        path[pathSize] = nums[i];
        backtrack(nums, numsSize, i + 1, result, returnSize, returnColumnSizes, path, pathSize + 1);
    }
}
int** subsetsWithDup(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    *returnSize = 0;
    qsort(nums, numsSize, sizeof(int), compare);
    int** result = malloc(1024 * sizeof(int*));
    *returnColumnSizes = malloc(1024 * sizeof(int));
    int* path = malloc(numsSize * sizeof(int)); 
    backtrack(nums, numsSize, 0, result, returnSize, *returnColumnSizes, path, 0);
    free(path);
    return result;
}

学习反思

实现了生成一个包含重复元素的数组的所有子集的功能。与之前的代码相比,主要的变化在于在回溯的过程中加入了去重操作。

  1. 在主函数subsetsWithDup中,首先对输入的数组进行排序,以便在后续的回溯过程中去重。通过调用qsort函数,使用自定义的比较函数对数组进行排序。

  2. 在回溯函数backtrack中,使用了一个判断条件来跳过重复元素。如果当前的元素与前一个元素相同,并且不是起始位置,就跳过这个元素。这样可以避免生成重复的子集。

总结

对回溯算法有了更深刻的认识,加油!!!

 

标签:numsSize,returnSize,int,Day24,nums,随想录,算法,result,path
From: https://blog.csdn.net/a6666999d/article/details/143196078

相关文章

  • 视频监控ai垃圾箱满溢监测算法系统
    视频监控AI垃圾箱满溢监测算法系统基于先进的AI智能算法,视频监控ai垃圾箱满溢监测算法系统在垃圾投放点安装了AI监控摄像头和音柱设备,通过视频监控和智能分析算法实现对垃圾分类投放过程的实时监测和识别。系统可以识别垃圾乱投的情况,检测垃圾箱是否满溢,判断厨余垃圾是否破袋以及......
  • 代码随想录算法训练营 | 岛屿数量 深搜,岛屿数量 广搜,岛屿的最大面积
    岛屿数量深搜题目链接:岛屿数量深搜文档讲解︰代码随想录(programmercarl.com)日期:2024-10-23想法:Java代码如下:importjava.util.Scanner;publicclassMain{publicstaticint[][]dir={{0,1},{1,0},{-1,0},{0,-1}};publicstaticvoiddfs(boolean[][]v......
  • 【代码随想录Day50】图论Part02
    岛屿数量深搜题目链接/文章讲解:代码随想录classSolution{//计算网格中岛屿的数量publicintnumIslands(char[][]grid){intsum=0;//初始化岛屿数量为0//遍历整个网格for(inti=0;i<grid.length;i++){......
  • 【数据结构与算法】之龟兔赛跑算法
    目录一、龟兔赛跑算法1.1阶段11.2阶段21.3为什么呢?二、判断是否有环2.1问题描述2.2示例2.3 代码实现三、找到环入口3.1问题描述3.2示例3.3代码实现总结本文主要介绍以环形链表相关的算法,主要采用Java语言实现,这类算法又称Floyd'sTortoiseandHare......
  • 基于三帧差算法的运动目标检测系统FPGA实现,包含testbench和MATLAB辅助验证程序
    1.算法运行效果图预览(完整程序运行后无水印)   将FPGA的仿真结果导入到MATLAB中,分别得到MATLAB的结果和FPGA的结果:   2.算法运行软件版本vivado2019.2 matlab2022a 3.部分程序(完整版代码包含详细中文注释和操作步骤视频)`timescale1ns/1ps////C......
  • 【图论】(五)最短路径算法(D / BF / SPFA / F / A*)
    最短路径算法(D/BF/SPFA/F/A*)1.最短路径之dijkstra(D算法)思路模拟过程程序实现拓展2.dijkstra算法堆优化思路程序实现3.Bellman_ford算法(BF算法)松弛模拟过程拓展4.Bellman_ford队列优化算法(又名SPFA)模拟过程拓展5.Bellman_ford之判断负权回路思路拓展6......
  • 磁盘和磁盘调度算法
    磁盘的结构如果内道和外道扇区数量一样,那么磁盘的存储能力受限于内道的最大记录密度。而为了提高磁盘的存储容量,充分利用磁盘外层磁道的存储能力,现代磁盘不再将内外磁道划分为相同数目的扇区,而是将盘面划分为若干换代,同一环带内的所有磁道具有相同的扇区数,显然,外层环带的磁道......
  • 【算法笔记】前缀和算法原理深度剖析(超全详细版)
    【算法笔记】前缀和算法原理深度剖析(超全详细版)......
  • 代码随想录第七天
    454.四数相加II给你四个整数数组nums1、nums2、nums3和nums4,数组长度都是n,请你计算有多少个元组(i,j,k,l)能满足:0<=i,j,k,l<nnums1[i]+nums2[j]+nums3[k]+nums4[l]==0示例1:输入:nums1=[1,2],nums2=[-2,-1],nums3=[-1,2],nums4=[0,......
  • 代码训练营第22天|补第9天的KMP算法,28. 找出字符串中第一个匹配项的下标|459.重复的子
    前置知识文章链接:https://programmercarl.com/0028.实现strStr.html#思路KMP的经典思想就是:当出现字符串不匹配时,可以记录一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配。前缀表:next数组就是一个前缀表(prefixtable)。前缀表是用来回退的,它记录了模式串与主......