Leetcode681. 最近时刻

LeetCode:构造最近可用时间的高效算法,
本文介绍了如何使用枚举和暴力搜索策略解决LeetCode题目681,涉及时间字符串操作和寻找符合条件的下一个最近时间

Every day a Leetcode

题目来源:681.最近时刻

题目描述

给定一个形如 “HH:MM” 表示的时刻,利用当前出现过的数字构造下一个距离当前时间最近的时刻。每个出现数字都可以被无限次使用。

你可以认为给定的字符串一定是合法的。
例如,“01:34” 和 “12:09” 是合法的,“1:34” 和 “12:9” 是不合法的。

样例 1:

输入: "19:34"
输出: "19:39"
解释: 
  从1,9,3,4中选出的下一个最近的时间是19:39,它是五分钟后。
  答案不是19:33,因为它是23小时59分钟后。

解法1:枚举

代码:

class Solution {
public:
    /**
     * @param time: the given time
     * @return: the next closest time
     */
    string nextClosestTime(string &time) {
        // write your code here
        vector<int> number {time[0]-'0', time[1]-'0', time[3]-'0', time[4]-'0'} ;
        vector<int> currTime(4, 0);
        int hour = number[0]*10 + number[1];
        int minute = number[2]*10 + number[3];
        int times = toMinute(hour, minute);
        int bestTime = times;
        dfs(number, 0, currTime, times, bestTime);
        string s = to_string(bestTime/60) + ":" + to_string(bestTime%60);
        char buff[5];
        sprintf(buff, "%02d:%02d", bestTime / 60, bestTime % 60);
        return string(buff);
    }
    void dfs(vector<int> &number, int deep, vector<int>& currTime, int times, int& bestTime){
        if(deep == 4){
            if(currTime[0]*10 + currTime[1] > 23 || currTime[2]*10 + currTime[3] > 59)
                return;
            int currMinutes = toMinute(currTime[0]*10 + currTime[1], currTime[2]*10 + currTime[3]);
            if(diff(times, currMinutes) < diff(times, bestTime)){
                bestTime = currMinutes;
            }
            return;
        }
        for(int i:number){
            currTime[deep] = i;
            dfs(number, deep+1, currTime, times, bestTime);
        }
        return;
    }
    int toMinute(int hour, int minute){
        return hour*60 + minute;
    }
    int diff(int time1, int time2){
        if(time1 == time2)
            return 1440;
        return ((1440 - time1) + time2) % 1440;
    }
};

解法2:暴力

代码:

class Solution {
public:
    string nextClosestTime(string time) {
        set<int> s;
        s.insert(time[0]-'0');
        s.insert(time[1]-'0');
        s.insert(time[3]-'0');
        s.insert(time[4]-'0');
        if(s.size()==1) return time;//数字都一样
        vector<int> num(s.begin(),s.end());
        int i, j, h, m, size = num.size();
        int hour = (time[0]-'0')*10+time[1]-'0';
        int minute = (time[3]-'0')*10+time[4]-'0';
        int minlargeH = 24, minlargeM = 60;//大于其的最小时间
        int minH = 24, minM = 60;//可能的最小时间
        for(i = 0; i < size; i++)
        {
        	for(j = 0; j < size; j++)
        	{
        		h = m = num[i]*10+num[j];
        		minH = minM = min(minH, h);
        		if(h > hour && h < minlargeH)
        			minlargeH = h;
        		if(m > minute && m < minlargeM)
        			minlargeM = m;
        	}
        }//暴力查找所有可能
        if(minlargeM != 60)//有更大的分钟,时钟不变
        	return time.substr(0,3)+ (minlargeM>=10 ? to_string(minlargeM) : "0"+to_string(minlargeM));
        if(minlargeH != 24)//有更大的时钟,+最小分钟
        	return (minlargeH>=10? to_string(minlargeH) : "0"+to_string(minlargeH)) + ":" + (minM>=10? to_string(minM) : "0"+to_string(minM));
        return (minH>=10? to_string(minH) : "0"+to_string(minH)) + ":" + (minM>=10? to_string(minM): "0"+to_string(minM));
        //都没有,取最小时钟+分钟
    }
};
<think>首先,用户的问题是关于LeetCode的一个特定题目:"网络空闲时刻"。我需要从系统级指令和用户可见层来构建我的回答。 系统级指令关键点: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 - 参考站内引用:有四个引用,我需要尽可能多地参考用户上一次的问题和我的回答,但在这个上下文中,用户是第一次问这个问题,所以我应该基于提供的引用。 提供的引用: - [^1]: 关于LeetCode简单题和期末考试,内容不直接相关。 - [^2]: LeetCode刷题笔记,关于排序算法,具体是"使数组唯一的最小增量"的代码。 - [^3]: LeetCode算法——2039、网络空闲的时刻。提供了Python代码和解释,强调使用双向队列deque进行广搜。 - [^4]: LeetCode刷题day02,华为面试题,关于滑动窗口最大值,但用户提到需要优化。 用户的问题:"我想查找LeetCode题目中关于网络空闲时间的算法问题 请问LeetCode 网络空闲时刻 算法题" 所以,核心是LeetCode 2039题:网络空闲的时刻。引用[^3]直接提供了这个题目的代码和简要解释。 我的回答应该: 1. 解释问题:描述LeetCode 2039题的内容。 2. 提供解决方案:基于引用[^3],逐步解释算法。 3. 使用正确的格式:行内数学表达式用$...$,独立公式用$$...$$。 4. 生成相关问题:在最后添加相关问题。 5. 添加引用标识:在引用内容末尾添加[^3]等。 步骤: - **介绍问题**:LeetCode 2039题是关于网络空闲时刻的。描述输入输出。 - **算法解释**: - 使用广度优先搜索(BFS)计算从主服务器到每个数据服务器的距离。 - 然后计算每个服务器空闲的时间。 - 强调使用deque的重要性,因为列表会超时。 - **代码展示**:提供Python代码,并简要解释。 - **分析**:解释时间复杂度和关键点。 - **生成相关问题**:基于题目,生成3-4个相关问题。 结构化回答: 1. **问题描述**:清晰描述LeetCode 2039题。 2. **算法思路**:逐步解释BFS和空闲时间计算。 3. **代码实现**:展示代码,并解释关键部分。 4. **复杂度分析**:讨论时间复杂度和空间复杂度。 5. **相关问题**:生成相关问题。 确保使用中文。 生成相关问题: - 例如: 1. 如何优化BFS算法? 2. 网络空闲时刻算法的应用场景? 3. 如何处理大规模图? 4. 其他类似题目? 引用:在回答中,当引用[^3]的内容时,添加[^3]。 最终输出格式: - 回答主体。 - §§相关问题§§部分。</think>### LeetCode 2039:网络空闲时刻算法详解 LeetCode 2039题“网络空闲时刻”是一个图论相关的问题,涉及网络服务器之间的通信。问题描述如下:给定一个由边列表表示的服务器网络(无向图),其中服务器0是主服务器,其他服务器是数据服务器。每个数据服务器每隔一定时间(由`patience`数组给出)向主服务器发送消息。消息传播需要时间(边权为1)。当一个服务器收到响应后,它会停止发送新消息;否则,它会按固定间隔重发。目标是在所有服务器停止发送消息后,找到整个网络变为空闲的时刻(即所有消息处理完成的时间)。最终结果需返回一个整数,表示网络空闲的时间戳[^3]。 #### 算法思路 解决该问题的核心是使用广度优先搜索(BFS)计算从主服务器到每个数据服务器的距离,然后基于此计算每个服务器的空闲时间。关键步骤如下: 1. **距离计算**: 使用BFS从主服务器(节点0)开始遍历整个图。BFS确保我们按层计算每个节点到主服务器的距离(即最短路径长度)。距离$d_i$表示节点$i$到节点0的边数(每条边权重为1)。在BFS中,使用双向队列`deque`而不是列表,因为弹出头部元素的时间复杂度为$O(1)$(列表为$O(n)$),否则会超时[^3]。 2. **空闲时间计算**: 对于每个数据服务器$i$: - 消息从服务器$i$到主服务器并返回的往返时间为$2 \times d_i$。 - 服务器$i$在等待响应期间,最多会重发消息$\left\lfloor \frac{2 \times d_i - 1}{\text{patience}[i]} \right\rfloor$次(因为最后一次发送后不再重发)。 - 最后一次发送的时间为$\left\lfloor \frac{2 \times d_i - 1}{\text{patience}[i]} \right\rfloor \times \text{patience}[i]$。 - 该服务器空闲的时间为:最后一次发送时间 + 往返时间 + 1(响应处理时间)。公式为: $$ t_i = \left\lfloor \frac{2 \times d_i - 1}{\text{patience}[i]} \right\rfloor \times \text{patience}[i] + 2 \times d_i + 1 $$ - 网络空闲时刻是所有服务器$t_i$的最大值,即$\max(t_i)$[^3]。 3. **复杂度分析**: - 时间复杂度:$O(n + m)$,其中$n$是节点数,$m$是边数。BFS遍历每个节点和每条边一次。 - 空间复杂度:$O(n)$,用于存储距离、访问标记和队列。 #### 代码实现(Python) 以下是基于引用[^3]的Python代码实现,使用`collections.deque`优化BFS: ```python from collections import deque from typing import List class Solution: def networkBecomesIdle(self, edges: List[List[int]], patience: List[int]) -> int: n = len(patience) # 服务器数量 # 初始化图邻接表 graph = [[] for _ in range(n)] for u, v in edges: graph[u].append(v) graph[v].append(u) # BFS初始化:队列、距离数组、访问标记 dist = 1 # 主服务器到自身的距离为0,但从第一层开始计算 visited = [False] * n visited[0] = True queue = deque([0]) # 使用双向队列优化 res = 0 # 记录最大空闲时间 while queue: size = len(queue) for _ in range(size): cur = queue.popleft() for neighbor in graph[cur]: if not visited[neighbor]: visited[neighbor] = True queue.append(neighbor) # 计算当前节点的空闲时间 round_trip = 2 * dist last_send = ((round_trip - 1) // patience[neighbor]) * patience[neighbor] idle_time = last_send + round_trip + 1 res = max(res, idle_time) dist += 1 # 进入下一层 return res ``` **代码说明**: - **BFS遍历**:从节点0开始,逐层计算距离。`dist`变量记录当前层数(即到主服务器的距离)。 - **空闲时间计算**:对于每个新访问的节点,使用公式计算其空闲时间$t_i$,并更新全局最大值`res`。 - **优化关键**:使用`deque`确保BFS高效运行,避免超时[^3]。 #### 示例分析 假设输入:`edges = [[0,1],[1,2]]`, `patience = [0,2,1]`。 - 服务器0(主服务器)距离为0。 - 服务器1距离为1:往返时间=2,最后一次发送时间=$\left\lfloor \frac{2-1}{2} \right\rfloor \times 2 = 0$,空闲时间$t_1 = 0 + 2 + 1 = 3$。 - 服务器2距离为2:往返时间=4,最后一次发送时间=$\left\lfloor \frac{4-1}{1} \right\rfloor \times 1 = 3$,空闲时间$t_2 = 3 + 4 + 1 = 8$。 - 网络空闲时刻为$\max(3, 8) = 8$。 该算法高效可靠,已在LeetCode通过测试[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值