Leecode刷题C语言之我的日程安排表③

执行结果:通过

执行用时和内存消耗如下:

复制代码
typedef struct {
    int size;
    int maxIntersection;
    int** books;
    // #ifdef DEBUG
    // int runCount;
    // #endif
} MyCalendarThree;

void insert(MyCalendarThree*, int, int, int, int);
int* binarySearch(int*, int, int);

MyCalendarThree* myCalendarThreeCreate() {
    MyCalendarThree* newCal = (MyCalendarThree*)malloc(sizeof(MyCalendarThree));
    newCal -> size = 0;
    newCal -> maxIntersection = 0;
    newCal -> books = (int**)malloc(sizeof(int*) * 2);
    for (int i = 0; i < 2; i++) {
        (newCal -> books)[i] = (int*)malloc(sizeof(int) * 400);
    }
    // #ifdef DEBUG
    // newCal -> runCount = 0;
    // #endif

    return newCal;
}

int myCalendarThreeBook(MyCalendarThree* obj, int startTime, int endTime) {
    //printf("New Process\n");
    int* sLoc = binarySearch((obj -> books)[0], obj -> size, startTime);
    int* eLoc = binarySearch((obj -> books)[1], obj -> size, startTime);
    int initialSLoc = (int)(sLoc - (obj -> books)[0]);
    int eeLoc = (int)(binarySearch((obj -> books)[1], obj -> size, endTime) - (obj -> books)[1]);
    //printf("Initial: %d, %d\n", initialSLoc, (int)(eLoc - (obj -> books)[1]));
    int count = initialSLoc - (int)(eLoc - (obj -> books)[1]) + 1;
    // #ifdef DEBUG
    // DEBUG(9);
    // #endif
    while (*sLoc < endTime) {
        if (count > obj -> maxIntersection) obj -> maxIntersection = count;
        if ((int)(sLoc - (obj -> books)[0]) >= obj -> size) {
            break;
        }
        //printf("count: %d\n", count);
        if (*sLoc < *eLoc) { sLoc++; count++; }
        else { eLoc++; count--; }
    }
    if (count > obj -> maxIntersection) obj -> maxIntersection = count;
    insert(obj, startTime, endTime, initialSLoc, eeLoc);
    //printf("True, size=%d\n", obj -> size);
    return obj -> maxIntersection;
}

void myCalendarThreeFree(MyCalendarThree* obj) {
    for (int i = 0; i < 2; i++) {
        free((obj -> books)[i]);
    }
    free(obj -> books);
    free(obj);
}

/**
 * Your MyCalendarThree struct will be instantiated and called as such:
 * MyCalendarThree* obj = myCalendarThreeCreate();
 * int param_1 = myCalendarThreeBook(obj, startTime, endTime);
 
 * myCalendarThreeFree(obj);
*/

int* binarySearch(int* arr, int size, int target) {
    int l = 0;
    int r = size - 1;
    while (l <= r) {
        int i = (l + r) / 2;
        if (target >= arr[i]) l = i + 1;
        else r = i - 1;
    }
    return arr + l;
}

void insert(MyCalendarThree* obj, int startTime, int endTime, int sIdx, int eIdx) {
    memmove(
        (obj -> books)[0] + sIdx + 1,
        (obj -> books)[0] + sIdx,
        (obj -> size - sIdx) * sizeof(int)
    );
    memmove(
        (obj -> books)[1] + eIdx + 1,
        (obj -> books)[1] + eIdx,
        (obj -> size - eIdx) * sizeof(int)
    );
    (obj -> books)[0][sIdx] = startTime;
    (obj -> books)[1][eIdx] = endTime;
    (obj -> size)++;
}

解题思路:

这段代码实现了一个名为 MyCalendarThree 的数据结构,用于跟踪在一段时间内(由开始时间和结束时间定义)的日程安排,并计算在任何给定时间点同时存在的最大日程数。下面是代码的思路分析:

数据结构定义

  • MyCalendarThree 结构体包含以下成员:
    • int size:当前已存储的日程数量。
    • int maxIntersection:在任何给定时间点同时存在的最大日程数。
    • int** books:一个二维数组,其中 books[0] 存储所有日程的开始时间,books[1] 存储所有日程的结束时间。这样做可以方便地通过二分查找定位开始和结束时间。
    • 注释掉的 #ifdef DEBUG 部分用于调试,不在生产代码中启用。

函数实现

  1. myCalendarThreeCreate
    • 分配并初始化 MyCalendarThree 结构体。
    • 初始化 size 为 0,maxIntersection 为 0。
    • books 分配内存,初始化为存储两个包含 400 个整数的数组(预设大小,可以根据需要调整)。
    • 返回创建的 MyCalendarThree 实例。
  2. binarySearch
    • 在给定的数组 arr 中查找第一个大于或等于 target 的元素的指针。
    • 使用二分查找算法提高查找效率。
    • 返回指向找到的位置的指针。
  3. myCalendarThreeBook
    • 使用 binarySearch 找到新日程的开始时间和结束时间在 books 中的位置。
    • 计算初始的重叠数量(基于二分查找结果)。
    • 遍历受影响的日程区间,更新 maxIntersection,并根据需要调整 count(重叠数量)。
    • 使用 insert 函数将新日程的开始和结束时间插入到 books 中。
    • 返回当前的 maxIntersection
  4. insert
    • 使用 memmove 函数为新的日程在 books 数组中腾出空间。
    • 将新日程的开始和结束时间插入到正确的位置。
    • 更新 size
  5. myCalendarThreeFree
    • 释放 MyCalendarThree 结构体中分配的所有内存。

使用流程

  • 创建一个 MyCalendarThree 实例。
  • 使用 myCalendarThreeBook 函数添加日程,并获取当前的 maxIntersection
  • 当不再需要时,使用 myCalendarThreeFree 释放 MyCalendarThree 实例占用的内存。

关键点

  • 时间复杂度
    • binarySearch:O(log n),其中 n 是 books 中的日程数量。
    • myCalendarThreeBook:在最坏情况下,需要遍历所有日程来计算重叠,但由于使用了二分查找定位新日程的位置,所以整体复杂度仍较低。
  • 空间复杂度
    • 预设了 400 个元素的数组来存储日程的开始和结束时间,这是根据预期使用情况进行的一个折衷。如果日程数量超过这个预设值,可能需要重新设计数据结构以动态扩展数组。
相关推荐
艾莉丝努力练剑6 小时前
【洛谷刷题】用C语言和C++做一些入门题,练习洛谷IDE模式:分支机构(一)
c语言·开发语言·数据结构·c++·学习·算法
Cx330❀7 小时前
【数据结构初阶】--排序(五):计数排序,排序算法复杂度对比和稳定性分析
c语言·数据结构·经验分享·笔记·算法·排序算法
..过云雨8 小时前
01.【数据结构-C语言】数据结构概念&算法效率(时间复杂度和空间复杂度)
c语言·数据结构·笔记·学习
谱写秋天10 小时前
在STM32F103上进行FreeRTOS移植和配置(STM32CubeIDE)
c语言·stm32·单片机·freertos
我不是板神10 小时前
程序设计|C语言教学——C语言基础2:计算与控制语句
c语言
基于python的毕设10 小时前
C语言栈的实现
linux·c语言·ubuntu
promising-w14 小时前
【嵌入式C语言】六
c语言·开发语言
ankleless15 小时前
C语言(11)—— 数组(超绝详细总结)
c语言·零基础·数组·二维数组·自学·一维数组
草莓熊Lotso16 小时前
《吃透 C++ 类和对象(中):const 成员函数与取地址运算符重载解析》
c语言·开发语言·c++·笔记·其他
野生的编程萌新18 小时前
从冒泡到快速排序:探索经典排序算法的奥秘(二)
c语言·开发语言·数据结构·c++·算法·排序算法