在问 · 算法题解

636. 函数的独占时间

题目描述

一个单线程 CPU 上运行着 n 个函数,编号为 0 到 n - 1。函数之间可以互相调用,也可以递归调用自己,同一个函数可以被调用多次。调用关系按栈来管理:函数开始时压栈,结束时出栈,任何时刻只有栈顶的函数在执行。

输入整数 n 和按时间先后排列的日志数组 logs。每条日志是形如 "编号:start:时间戳" 或 "编号:end:时间戳" 的字符串。start 表示该函数在这个时间单位的开头开始运行;end 表示它在这个时间单位的末尾结束,因此这个时间单位本身也算它的执行时间。

一个函数的独占时间,是它在所有调用中真正位于栈顶执行的时间之和,被它调用的其他函数运行的时间不计入。

返回长度为 n 的数组,下标 i 处是编号为 i 的函数的独占时间。

示例 1
输入:n = 2
logs = ["0:start:0","1:start:2","1:end:5","0:end:6"]
输出:[3,4]

解释:函数 0 在时间 0 到 1 执行 2 个单位,函数 1 在时间 2 到 5 执行 4 个单位,函数 0 在时间 6 再执行 1 个单位,合计 [3,4]。

示例 2
输入:n = 1
logs = ["0:start:0","0:start:2","0:end:5","0:start:6","0:end:6","0:end:7"]
输出:[8]

解释:函数 0 的初始调用共执行 2 + 1 = 3 个单位,两次递归调用分别执行 4 和 1 个单位,总计 8。

示例 3
输入:n = 2
logs = ["0:start:0","0:start:2","0:end:5","1:start:6","1:end:6","0:end:7"]
输出:[7,1]

解释:函数 0 两次调用合计 2 + 4 + 1 = 7 个单位,函数 1 在时间 6 执行 1 个单位。

数据范围

  • 1 <= n <= 100
  • 2 <= logs.length <= 500
  • 0 <= function_id < n
  • 0 <= timestamp <= 10^9
  • 不会有两个 start 事件出现在同一时间戳。
  • 不会有两个 end 事件出现在同一时间戳。
  • 每个函数的 start 日志都有与之配对的 end 日志。

解题思路

函数调用天然是栈结构:栈顶就是正在运行的函数。用 prev 记录“上一段时间从哪个时间单位开始”。遇到 start:从 prev 到 ts-1 这段时间属于当前栈顶,累加 ts - prev,然后新函数入栈,prev = ts。遇到 end:从 prev 到 ts(含)属于栈顶,累加 ts - prev + 1 并出栈,下一段从 ts+1 开始。

为什么正确

时间单位 0..prev-1 都已经计入某个函数;栈从底到顶是当前的调用链,栈顶正在运行。

复杂度分析

时间 O(m),m 为日志条数;空间 O(m)(栈)。

易错点

start 的时间戳指时间单位的开头,end 的时间戳指时间单位的末尾,所以 end 要 +1,且之后 prev = ts + 1。同一个函数可以递归调用自己,累加到同一个 res 上即可。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def exclusiveTime(self, n: int, logs: List[str]) -> List[int]:
        res = [0] * n
        stack = []
        prev = 0
        for log in logs:
            fid, typ, ts = log.split(':')
            fid, ts = int(fid), int(ts)
            if typ == 'start':
                if stack:
                    res[stack[-1]] += ts - prev
                stack.append(fid)
                prev = ts
            else:
                res[stack.pop()] += ts - prev + 1
                prev = ts + 1
        return res

载入编辑器,自己跑一遍 →

栈与堆 专题的其他题目

查看 栈与堆 全部题目 →