JavaScript / TypeScript / PHP / Golang / Python / Java / C# / C / C++ 栈,求解《636. 函数的独占时间》

2022-08-07 12:23:18

JavaScript / TypeScript / PHP / Golang / Python / Java / C# / C / C++ 栈,split / sscanf 指定字符分割字符串,+ / Integer.Parse / int.Parse / int / atoi / Atoi 字符串转数字,求解《636. 函数的独占时间》

例题

636. 函数的独占时间

有一个 单线程 CPU 正在运行一个含有 n 道函数的程序。每道函数都有一个位于 0 和 n-1 之间的唯一标识符。
函数调用 存储在一个 调用栈 上 :当一个函数调用开始时,它的标识符将会推入栈中。而当一个函数调用结束时,它的标识符将会从栈中弹出。标识符位于栈顶的函数是 当前正在执行的函数 。每当一个函数开始或者结束时,将会记录一条日志,包括函数标识符、是开始还是结束、以及相应的时间戳。
给你一个由日志组成的列表 logs ,其中 logs[i] 表示第 i 条日志消息,该消息是一个按 "{function_id}:{"start" | "end"}:{timestamp}" 进行格式化的字符串。例如,"0:start:3" 意味着标识符为 0 的函数调用在时间戳 3 的 起始开始执行 ;而 "1:end:2" 意味着标识符为 1 的函数调用在时间戳 2 的 末尾结束执行。注意,函数可以 调用多次,可能存在递归调用 。
函数的 独占时间 定义是在这个函数在程序所有函数调用中执行时间的总和,调用其他函数花费的时间不算该函数的独占时间。例如,如果一个函数被调用两次,一次调用执行 2 单位时间,另一次调用执行 1 单位时间,那么该函数的 独占时间 为 2 + 1 = 3 。
以数组形式返回每个函数的 独占时间 ,其中第 i 个下标对应的值表示标识符 i 的函数的独占时间。 示例 1: 636. 函数的独占时间示例 1 配图
输入:n = 2, logs = ["0:start:0","1:start:2","1:end:5","0:end:6"]
输出:[3,4]
解释:
函数 0 在时间戳 0 的起始开始执行,执行 2 个单位时间,于时间戳 1 的末尾结束执行。
函数 1 在时间戳 2 的起始开始执行,执行 4 个单位时间,于时间戳 5 的末尾结束执行。
函数 0 在时间戳 6 的开始恢复执行,执行 1 个单位时间。
所以函数 0 总共执行 2 + 1 = 3 个单位时间,函数 1 总共执行 4 个单位时间。

答案

var exclusiveTime = function(n, logs) {
  const r = new Array(n).fill(0), m = logs.length, st = []
  let prevTime = 0, prevSign = ''
  for (let i = 0; i < m; i++) {
    const t = logs[i].split(':'), cur = +t[0], sign = t[1], time = +t[2]
    if (sign === 'start') {
      if (st.length) r[st[st.length - 1]] += time - prevTime - (prevSign === 'start' ^ 1)
      st.push(cur)
    } else {
      r[cur] += time - prevTime + (prevSign === 'end' ^ 1)
      st.pop()
    }
    prevTime = time
    prevSign = sign
  }
  return r
};
var exclusiveTime = function(n, logs) { // 虚拟栈 · 指针模拟栈
  const r = new Array(n).fill(0), m = logs.length, st = new Array(m)
  let prevTime = 0, prevSign = '', j = 0
  for (let i = 0; i < m; i++) {
    const t = logs[i].split(':'), cur = +t[0], sign = t[1], time = +t[2]
    if (sign === 'start') {
      if (j > 0) r[st[j - 1]] += time - prevTime - (prevSign === 'start' ^ 1)
      st[j++] = cur
    } else {
      r[cur] += time - prevTime + (prevSign === 'end' ^ 1)
      j--
    }
    prevTime = time
    prevSign = sign
  }
  return r
};
function exclusiveTime(n: number, logs: string[]): number[] {
  const r = new Array(n).fill(0), m = logs.length, st = []
  let prevSign = '', prevTime = 0
  for (let i = 0; i < m; i++) {
    const t = logs[i].split(':'), cur = +t[0], sign = t[1], time = +t[2]
    if (sign === 'start') {
      if (st.length) r[st[st.length - 1]] += time - prevTime - (prevSign === 'start' ? 0 : 1)
      st.push(cur)
    } else {
      r[cur] += time - prevTime + (prevSign === 'start' ? 1 : 0)
      st.pop()
    }
    prevSign = sign
    prevTime = time
  }
  return r
};
class Solution {
  function exclusiveTime($n, $logs) {
    $r = array_fill(0, $n, 0);
    $st = [];
    $prevSign = '';
    $prevTime = 0;
    foreach ($logs as $log) {
      list($cur, $sign, $time) = explode(':', $log);
      if ($sign === 'start') {
        if (count($st)) $r[end($st)] += $time - $prevTime - ($prevSign === 'start' ^ 1);
        $st []= $cur;
      } else {
        $r[$cur] += $time - $prevTime + ($prevSign === 'end' ^ 1);
        array_pop($st);
      }
      $prevSign = $sign;
      $prevTime = $time;
    }
    return $r;
  }
}
func exclusiveTime(n int, logs []string) []int {
  r, prevSign, prevTime, st := make([]int, n), "", 0, []int{}
  for _, log := range logs {
    t := strings.Split(log, ":")
    cur, _ := strconv.Atoi(t[0])
    sign := t[1]
    time, _ := strconv.Atoi(t[2])
    if sign == "start" {
      if len(st) > 0 {
        r[st[len(st) - 1]] += time - prevTime - btoi(prevSign == "end")
      }
      st = append(st, cur)
    } else {
      r[cur] += time - prevTime + btoi(prevSign == "start")
      st = st[:len(st) - 1]
    }
    prevSign = sign
    prevTime = time
  }
  return r
}
func btoi (b bool) int {
  if b {
    return 1
  }
  return 0
}
class Solution {
  public int[] exclusiveTime(int n, List<String> logs) {
    int[] r = new int[n];
    Deque<Integer> st = new ArrayDeque<Integer>();
    String prevSign = "";
    int prevTime = 0;
    for (String log : logs) {
      String[] t = log.split(":");
      int cur = Integer.parseInt(t[0]);
      String sign = t[1];
      int time = Integer.parseInt(t[2]);
      if (sign.equals("start")) {
        if (st.isEmpty() == false) r[st.peek()] += time - prevTime - btoi(prevSign.equals("end"));
        st.push(cur);
      } else {
        r[cur] += time - prevTime + btoi(prevSign.equals("start"));
        if (st.isEmpty() == false)  st.pop();
      }
      prevSign = sign;
      prevTime = time;
    }
    return r;
  }
  private int btoi (boolean b) {
    return b ? 1 : 0;
  }
}
public class Solution {
  public int[] ExclusiveTime(int n, IList<string> logs) {
    int[] r = new int[n];
    Stack<int> st = new Stack<int>();
    string prevSign = "";
    int prevTime = 0;
    foreach(string log in logs) {
      string[] t = log.Split(":");
      int cur = int.Parse(t[0]);
      string sign = t[1];
      int time = int.Parse(t[2]);
      if (sign == "start") {
        if (st.Count > 0) r[st.Peek()] += time - prevTime - Atoi(prevSign == "end");
        st.Push(cur);
      } else {
        r[cur] += time - prevTime + Atoi(prevSign == "start");
        st.Pop();
      }
      prevSign = sign;
      prevTime = time;
    }
    return r;
  }
  private int Atoi(bool b) {
    return b ? 1 : 0;
  }
}
static inline int btoi (bool b) {
  return b ? 1 : 0;
}
int* exclusiveTime(int n, char ** logs, int logsSize, int* returnSize){
  int* r = malloc(sizeof(int) * n);
  memset(r, 0, sizeof(int) * n);
  int* st = malloc(sizeof(int) * logsSize);
  char prevSign;
  int prevTime = 0, head = 0;
  for (int i = 0; i < logsSize; i++) {
    char sign[6];
    int cur, time;
    sscanf(logs[i], "%d:%[^:]:%d", &cur, sign, &time);
    if (sign[0] == 's') {
      if (head > 0) r[st[head - 1]] += time - prevTime - btoi(prevSign == 'e');
      st[head++] = cur;
    } else {
      r[cur] += time - prevTime + btoi(prevSign == 's');
      head--;
    }
    prevSign = sign[0];
    prevTime = time;
  }
  free(st);
  *returnSize = n;
  return r;
}
class Solution {
public:
  vector<int> exclusiveTime(int n, vector<string>& logs) {
    vector<int> r(n, 0);
    stack<int> st;
    char prevSign;
    int prevTime = 0;
    for (string& log : logs) {
      int cur, time;
      char sign[6];
      sscanf(log.c_str(), "%d:%[^:]:%d", &cur, sign, &time);
      if (sign[0] == 's') {
        if (st.empty() == false) r[st.top()] += time - prevTime - (prevSign == 'e');
        st.push(cur);
      } else {
        r[cur] += time - prevTime + (prevSign == 's');
        st.pop();
      }
      prevSign = sign[0];
      prevTime = time;
    }
    return r;
  }
};
class Solution:
  def exclusiveTime(self, n: int, logs: List[str]) -> List[int]:
    r, st, prevSign, prevTime = [0] * n, [], "", 0
    for log in logs:
      cur, sign, time = log.split(':')
      cur, time = int(cur), int(time)
      if sign == "start":
        if len(st): r[st[len(st) - 1]] += time - prevTime - int(prevSign == "end")
        st.append(cur)
      else:
        r[cur] += time - prevTime + int(prevSign == "start")
        st.pop()
      prevSign = sign
      prevTime = time
    return r

顺序遍历字符串,双指针技巧,用 startsWith (javascript / typescript / java) / StartsWith (c#) / startswith (python) / str_starts_with (php) / strings.HasPrefix (golang)接口,求解《1455. 检查单词是否为句中其他单词的前缀》
顺序遍历字符串,双指针技巧,用 startsWith (javascript / typescript / java) / StartsWith (c#) / startswith (python) / str_starts_with (php) / strings.HasPrefix (golang) 接口,求解《1455. 检查单词是否为句中其他单词的前缀》
递归和单调递减栈 2 算法,用 数组 / Slice / ArrayDeque / Stack / int* / stack / vector / List 实现,求解《654. 最大二叉树》
递归和单调递减栈 2 算法,用 数组 / Slice / ArrayDeque / Stack / int* / stack / vector / List 实现,求解《654. 最大二叉树》
差分数组(TreeMap / redblacktree.NewWithIntComparator 红黑树)、顺序遍历、二分查找(upper_bound + bisect_right / lower_bound + bisect_left / sort.Search + sort.SearchInts) 3 种算法,用升序(sort / Arrays.sort / Array.Sort / qsort(int*, int, sizeof(int), cmp) / sort.Ints)技巧,求解《1450. 在既定时间做作业的学生人数》
差分数组(TreeMap / Object.create(null) / Array / redblacktree.NewWithIntComparator 红黑树)、顺序遍历、二分查找(upper_bound + bisect_right + sort.Search + sort.SearchInts / lower_bound + bisect_left + sort.Search + sort.SearchInts) 3 种算法,用升……