题目
解题思路:
函数的调用满足完全包含关系,可以使用栈来处理,函数开始调用则入栈,结束调用则出栈,想办法之前的一次函数操作时间即可。
函数独占时间指的是:当前函数从开始到结束时间段内没有再进行函数调用的时间段
函数调用(入栈)时,如果有父函数,那么就要结算父函数的独占时间(当前函数的调用时间-父函数的调用时间),如果没有父函数,直接入栈,记录时间即可。
函数结束(出栈)时,要立即结算其独占时间(结束时间-开始时间+1),如果有父函数,那么逻辑上当当前函数结束调用,父函数会在(当前函数结束时间+1)的时候恢复调用,正确得处理父函数的恢复调用时间是解题的关键。
代码
public static int[] exclusiveTime(int n, List<String> logs) {
int[] result = new int[n];//结果数组
Stack<Integer> Vid = new Stack<Integer>();//日志编号栈
Stack<Integer> Vtime = new Stack<Integer>();//日志时间栈,只关注栈顶元素(代表上次任务的状态时间)
for (int i = 0,pre=0; i < logs.size(); i++) { //循环遍历日志集
String[] str = logs.get(i).split(":");//拆分日志集
int id = Integer.parseInt(str[0]); //获得id
String status = str[1]; //获得状态
int time = Integer.parseInt(str[2]);//获得状态时间
switch (status){ //判断状态
case "start":
if(!Vid.empty()){
//如果栈非空,证明之前有一个任务开启了,那么之前的任务独占时间到此结束
//将这一段之前任务的独占时间获取(当前任务开始时间-之前任务的开始时间)并累加
result[Vid.peek()] = result[Vid.peek()]+time - Vtime.peek();
}
Vid.push(id);//任务入栈
Vtime.push(time);//状态时间入栈
break;
case "end":
Vid.pop();//任务出栈
//当前任务结束,将该任务的独占时间(当前任务结束时间-当前任务开始时间+1)获取并累加
result[id] = result[id] + (time - Vtime.peek()+ 1);
//入栈当前任务结束时间+1(当前任任务结束,其父任务恢复执行,执行开始的时间就是time+1)
Vtime.push(time+1);
break;
}
}
return result;
}
总结
- 遇到函数调用相关的题目时,可以优先往栈思考
- 遇到这种题,仔细处理每个时间点是关键