力扣题解815

大家好,欢迎来到无限大的频道。祝大家中秋节快乐​。

今日继续给大家带来力扣题解。

题目描述(困难)​:

公交路线

给你一个数组 routes ,表示一系列公交线路,其中每个 routes[i] 表示一条公交线路,第 i 辆公交车将会在上面循环行驶。

  • 例如,路线 routes[0] = [1, 5, 7] 表示第 0 辆公交车会一直按序列 1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ... 这样的车站路线行驶。

现在从 source 车站出发(初始时不在公交车上),要前往 target 车站。 期间仅可乘坐公交车。

求出 最少乘坐的公交车数量 。如果不可能到达终点车站,返回 -1 。

解题思路

  1. 图模型:

    • 将公交线路和站点视为图的节点和边。每个站点是一个节点,每条公交线路可以看作是连接多个站点的边。

    • 我们需要找出从 source 站点到 target 站点的最短路径(最少乘坐的公交车数量)。最短路径我们采用BFS算法

  2. 哈希映射:

    • 使用哈希映射(在这里是链表实现的数组)来存储每个站点对应的公交线路。这样可以快速查找经过某个站点的所有公交线路。

  3. 广度优先搜索(BFS):

    • 使用 BFS 来遍历图,因为 BFS 能够找到最短路径。

    • BFS 从起始站点开始,逐层访问所有相邻的节点(公交线路),直到找到目标站点。

详细步骤

  1. 检查起始和目标站点:

    • 如果 source 和 target 相同,直接返回 0,因为不需要乘坐公交车。

  2. 构建哈希映射:

    • 使用 createHashMap 创建一个大小为 MAX_STOPS 的哈希映射数组 stop_to_routes。

    • 遍历每条线路,将每个站点映射到经过该站点的线路上。

  3. BFS 初始化:

    • 创建一个队列 queue 来存储待访问的公交线路。

    • 使用 visitedRoutes 数组记录已访问的线路,使用 visitedStops 数组记录已访问的站点。

    • 将所有经过 source 的公交线路入队,并标记为已访问。

  4. BFS 遍历:

    • 记录当前层的大小 levelSize,并增加深度 depth。

    • 遍历当前层的所有线路:

    • 如果当前站点是 target,则返回当前深度(乘坐的公交车数量)。

    • 如果当前站点未被访问,标记为已访问,并将该站点所有经过的未访问线路入队。

    • 对于每条线路,遍历其经过的所有站点:

    • 使用 while 循环进行 BFS,只要队列不为空:

  5. 资源释放:

    • 如果遍历完所有线路仍未找到目标站点,释放所有动态分配的内存并返回 -1。

关键部分解释

  • 哈希映射的使用:

    • 通过哈希映射,将站点映射到线路,能够快速获取经过某个站点的所有公交线路,避免了重复遍历,提高了效率。

  • BFS 的实现:

    • BFS 的层次遍历特性确保了在找到目标站点时,返回的深度是最小的,即乘坐的公交车数量是最少的。

代码参考​:

// 定义结构用于保存每个站点经过的路线
typedef struct Node {
    int data;
    struct Node* next;
} Node;
​
Node** createHashMap(int size) {
    // 用于初始化动态大小的哈希表
    Node** map = (Node**)malloc(size * sizeof(Node*));
    for (int i = 0; i < size; i++) {
        map[i] = NULL;
    }
    return map;
}
​
void insertHashMap(Node** map, int key, int value) {
    // 将一个值插入到哈希表中
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = value;
    newNode->next = map[key];
    map[key] = newNode;
}
​
typedef struct {
    int *data;
    int front;
    int rear;
    int size;
    int capacity;
} Queue;
​
Queue* createQueue(int capacity) {
    // 初始化队列结构
    Queue* queue = (Queue*)malloc(sizeof(Queue));
    queue->capacity = capacity;
    queue->front = 0;
    queue->size = 0;
    queue->rear = capacity - 1;
    queue->data = (int*)malloc(capacity * sizeof(int));
    return queue;
}
​
int isFull(Queue* queue) {
    // 检查队列是否已满
    return (queue->size == queue->capacity);
}
​
int isEmpty(Queue* queue) {
    // 检查队列是否为空
    return (queue->size == 0);
}
​
void enqueue(Queue* queue, int item) {
    // 向队列中加入元素
    if (isFull(queue))
        return;
    queue->rear = (queue->rear + 1) % queue->capacity;
    queue->data[queue->rear] = item;
    queue->size = queue->size + 1;
}
​
int dequeue(Queue* queue) {
    // 从队列中移除元素
    if (isEmpty(queue))
        return -1;
    int item = queue->data[queue->front];
    queue->front = (queue->front + 1) % queue->capacity;
    queue->size = queue->size - 1;
    return item;
}
​
int numBusesToDestination(int** routes, int routesSize, int* routesColSize, int source, int target) {
    if (source == target) return 0;
​
    // Step 1: 使用哈希映射保存站点与线路的对应关系
    const int MAX_STOPS = 1000000;
    Node** stop_to_routes = createHashMap(MAX_STOPS);
    
    for (int i = 0; i < routesSize; i++) {
        for (int j = 0; j < routesColSize[i]; j++) {
            int stop = routes[i][j];
            insertHashMap(stop_to_routes, stop, i);
        }
    }
​
    // BFS初始化
    Queue* queue = createQueue(routesSize);
    int depth = 0;
    int* visitedRoutes = (int*)calloc(routesSize, sizeof(int));
    int* visitedStops = (int*)calloc(MAX_STOPS, sizeof(int));
​
    Node* current = stop_to_routes[source];
    while (current != NULL) {
        enqueue(queue, current->data);
        visitedRoutes[current->data] = 1;
        current = current->next;
    }
​
    while (!isEmpty(queue)) {
        int levelSize = queue->size;
        depth++;
​
        for (int i = 0; i < levelSize; i++) {
            int route = dequeue(queue);
​
            for (int j = 0; j < routesColSize[route]; j++) {
                int stop = routes[route][j];
                if (stop == target) {
                    free(visitedRoutes);
                    free(visitedStops);
                    free(queue->data);
                    free(queue);
                    for (int k = 0; k < MAX_STOPS; k++) {
                        Node* iter = stop_to_routes[k];
                        while (iter) {
                            Node* toFree = iter;
                            iter = iter->next;
                            free(toFree);
                        }
                    }
                    free(stop_to_routes);
​
                    return depth;
                }
                if (!visitedStops[stop]) {
                    visitedStops[stop] = 1;
                    Node* iter = stop_to_routes[stop];
                    while (iter != NULL) {
                        int nextRoute = iter->data;
                        if (!visitedRoutes[nextRoute]) {
                            enqueue(queue, nextRoute);
                            visitedRoutes[nextRoute] = 1;
                        }
                        iter = iter->next;
                    }
                }
            }
        }
    }
​
    // 资源释放
    free(visitedRoutes);
    free(visitedStops);
    free(queue->data);
    free(queue);
    for (int i = 0; i < MAX_STOPS; i++) {
        Node* iter = stop_to_routes[i];
        while (iter) {
            Node* toFree = iter;
            iter = iter->next;
            free(toFree);
        }
    }
    free(stop_to_routes);
​
    return -1;
}

时间复杂度:

  • 构建哈希映射: 对于每个站点,将其加入相应的线路列表中。总共需要遍历所有站点,即 O(sum(routesColSize))。

  • BFS搜索: 在最坏情况下,需要访问所有站点和所有线路。由于每个站点只会被访问一次,且每个线路也只会被访问一次,时间复杂度为 O(sum(routesColSize))。

  • 因此,整体时间复杂度为 O(sum(routesColSize))。

空间复杂度:

  • 哈希映射 stop_to_routes: 需要为每个站点存储经过的线路,最坏情况下为 O(sum(routesColSize))。

  • 队列: 最多需要存储所有线路,即 O(routesSize)。

  • 访问标记数组: visitedRoutes 大小为 O(routesSize),visitedStops 大小为 O(MAX_STOPS)。

  • 因此,整体空间复杂度为 O(sum(routesColSize) + routesSize + MAX_STOPS)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/879113.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】探索文件I/O奥秘,解锁软硬链接与生成动静态库知识

目录 1、C文件接口 1.1什么是当前路径&#xff1f; 1.2程序默认打开的文件流&#xff1a; 2、系统文件I/O 2.1.接口介绍&#xff1a; 2.1.1open&#xff1a; 参数讲解; flags如何实现一个参数就可以有多个参数传参的效果&#xff1f; open函数的返回值&#xff1a; 3…

SLAM面经1(百度)

百度面经 百度共三面,如果面试效果俱佳,会增加一个hr面。前二面主要是技术面,分为在线coding+代码知识+专业知识+工程能力。第三面是主管面,偏向于管理方面,和hr面相似。 一面 1)在线coding 在线coding的考试内容为下面力扣的变种。 2)专业面 (1)VINS-FUSION与ORB…

html+css+js网页设计 旅游 龙门石窟4个页面

htmlcssjs网页设计 旅游 龙门石窟4个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#…

SpringBoot3核心特性-核心原理

目录 传送门前言一、事件和监听器1、生命周期监听2、事件触发时机 二、自动配置原理1、入门理解1.1、自动配置流程1.2、SPI机制1.3、功能开关 2、进阶理解2.1、 SpringBootApplication2.2、 完整启动加载流程 三、自定义starter1、业务代码2、基本抽取3、使用EnableXxx机制4、完…

eclipse使用 笔记02

创建一个项目&#xff1a; 【File-->New-->Dynamic Web Project】 进入页面&#xff1a; Project name为项目命名 Target runtime&#xff1a;选择自己所对应的版本 finish创建成功&#xff1a; 创建成功后的删除操作&#xff1a; 创建前端界面&#xff1a; 【注意&a…

第十一章 【后端】商品分类管理微服务(11.1)——创建父工程

第十一章 【后端】商品分类管理微服务 11.1 创建父工程 项目名称:EasyTradeManagerSystem:Easy 表示简单易用,Trade 表示交易,Manager 表示管理,System 表示系统,强调系统在商品交易管理方面的便捷性,简称 etms。 新建工程 yumi-etms yumi-etms 作为所有模块的父工程,…

TortoiseSVN图标不显示的解决

解决办法一:修改svn软件的图标设置 1、选中一个文件夹或在桌面空白处,右击进入svn的setting 2、进入setting->Icon Overlays,Status cache选择Default或shell,然后点击应用 3、查看文件,图标可以正常显示 解决办法二:修改注册表的文件夹顺序 问题现象: 1、svn一直…

linux驱动开发-arm汇编基础

目录 写在前面 1、Cortex-A7 处理器有 9 种处理模式 2、Cortex-A 寄存器组 通用寄存器 1、汇编语法 2、Cortex-A7 常用汇编指令 2.1 处理器内部数据传输指令 2.1.1 传输数据操作类型 1、MOV指令 2、MRS指令 3、MSR指令 2.2、存储器访问指令 2.2.1 LDR指令 2.2.2 …

行车记录仪内存卡无法读取:问题解析与高效数据恢复策略

在智能出行的时代&#xff0c;行车记录仪作为车辆安全的守护者&#xff0c;其重要性不言而喻。然而&#xff0c;当行车记录仪的内存卡遭遇无法读取的困境时&#xff0c;不仅会影响行车记录仪的正常工作&#xff0c;更可能导致关键证据和美好回忆的丢失。本文将深入探讨行车记录…

基础 Web 开发

1. 构建项目&#xff1a; 2.添加依赖 <dependencies> <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupI…

Vue3 : ref 与 reactive

目录 一.ref 二.reactive 三.ref与reactive的区别 四.总结 一.ref 在 Vue 3 中&#xff0c;ref 是一个用于创建可读写且支持数据跟踪的响应式引用对象。它主要用于在组件内部创建响应式数据&#xff0c;这些数据可以是基本类型&#xff08;如 number、string、boolean&…

【卷起来】VUE3.0教程-09-整合Element-plus

最后一次课了&#xff0c;给个关注和赞呗 &#x1f332; 简介 Element Plus 是一个基于 Vue 3 的高质量 UI 组件库。它包含了丰富的组件和扩展功能&#xff0c;例如表格、表单、按钮、导航、通知等&#xff0c;让开发者能够快速构建高质量的 Web 应用。Element Plus 的设计理念…

在 Mac 上安装虚拟机怎么样,安装虚拟机与直接安装 Windows 系统有区别吗?

随着跨系统操作的不断发展&#xff0c;虚拟机技术在生产力领域扮演着越来越重要的角色。Mac作为一款主流的操作系统&#xff0c;也有着运行虚拟机的能力。接下来给大家介绍Mac装虚拟机好不好&#xff0c;Mac装虚拟机和装Windows系统一样吗的具体内容。 Mac装虚拟机好不好 Mac…

Flip动画的实现示例demo

Flip动画的实现示例demo 文章说明核心代码效果展示Flip动画工具类的封装 文章说明 文章主要为了学习flip动画的实现思路&#xff0c;并且采用此示例效果来理解该实现思路的含义 参考渡一前端袁老师的讲解视频 核心代码 采用简单的y轴变化的动画效果为示例 <!DOCTYPE html>…

Spring Boot 3项目使用Swagger3教程

Spring Boot 3项目使用Swagger3教程 Swagger&#xff1a;自动生成接口文档 添加依赖(pom.xml) <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.1…

基于双向RRT算法的三维空间最优路线规划matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 单向RRT算法 4.2 双向RRT算法 5.完整程序 1.程序功能描述 基于双向RRT&#xff08;Randomly Exploring Random Trees, 随机探索随机树&#xff09;算法的三维空间最优路径规划是一种解…

Linux 文件与目录操作命令详解

文章目录 前言创建文件1. touch2. vim 文件内容显示3. cat4. more5. less6. head7. tail 文件&#xff08;目录&#xff09;复制、删除和移动8. cp9. rm10. mv 压缩文件与解压缩11. gzip12. zip 和 unzip 创建目录13. mkdir 删除目录14. rmdir 改变工作目录15. cd16. pwd 显示目…

碰撞检测 | 图解线段几何与线段相交检测原理(附ROS C++可视化)

目录 0 专栏介绍1 线段与线段相交检测2 线段与圆相交检测3 线段与矩形相交检测4 算法仿真与可视化4.1 核心算法4.2 仿真实验 0 专栏介绍 &#x1f525;课设、毕设、创新竞赛必备&#xff01;&#x1f525;本专栏涉及更高阶的运动规划算法轨迹优化实战&#xff0c;包括&#xf…

吸浮毛宠物空气净化器推荐,希喂、小米、有哈宠物空气净化器测评

养猫需谨慎&#xff0c;不然就要做猫奴一辈子啦&#xff01;上次堂妹来我家住几天&#xff0c;刚开始还担心和猫处不来&#xff0c;不敢去摸它&#xff0c;走的时候已经约好下次来看它的时间&#xff0c;笑死我了。毕竟猫咪这么可爱&#xff0c;很少有人可以抵抗它的魅力。 这不…

想要一劳永逸地消除 AI 幻觉,该如何做?

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 尽管 LLMs 基于存储、检索和生成(RAG)的方法在某些情况下能够提供准确的回答,但在面对名词短语碰撞时,RAG方法可能会因为语义相似性而失效。为了解决这个问题,本文提出了命名实体过滤(NEF)作…