1. 程式人生 > >[LeetCode] Exclusive Time of Functions 函式的獨家時間

[LeetCode] Exclusive Time of Functions 函式的獨家時間

Given the running logs of n functions that are executed in a nonpreemptive single threaded CPU, find the exclusive time of these functions.

Each function has a unique id, start from 0 to n-1. A function may be called recursively or by another function.

A log is a string has this format : function_id:start_or_end:timestamp

. For example, "0:start:0" means function 0 starts from the very beginning of time 0. "0:end:0" means function 0 ends to the very end of time 0.

Exclusive time of a function is defined as the time spent within this function, the time spent by calling other functions should not be considered as this function's exclusive time. You should return the exclusive time of each function sorted by their function id.

Example 1:

Input:
n = 2
logs = 
["0:start:0",
 "1:start:2",
 "1:end:5",
 "0:end:6"]
Output:[3, 4]
Explanation:
Function 0 starts at time 0, then it executes 2 units of time and reaches the end of time 1. 
Now function 0 calls function 1, function 1 starts at time 2, executes 4 units of time and end at time 5.
Function 0 is running again at time 6, and also end at the time 6, thus executes 1 unit of time. 
So function 0 totally execute 2 + 1 = 3 units of time, and function 1 totally execute 4 units of time.

Note:

  1. Input logs will be sorted by timestamp, NOT log id.
  2. Your output should be sorted by function id, which means the 0th element of your output corresponds to the exclusive time of function 0.
  3. Two functions won't start or end at the same time.
  4. Functions could be called recursively, and will always end.
  5. 1 <= n <= 100

這道題讓我們函式的獨家執行的時間,沒錯,exclusive就是要翻譯成獨家,要讓每個函式都成為碼農的獨家記憶~哈~根據題目中給的例子,我們可以看出來,當一個函式start了之後,並不需要必須有end,可以直接被另一個程式start的時候強行關閉。而且,在某個時間點上呼叫end時,也不需要前面非得呼叫start,可以直接在某個時間點來個end,這樣也算執行了1秒,得+1秒~咳咳,本站禁“苟”,請勿輕易吟詩。博主自以為了解了這個題的邏輯,自己寫了一個,結果跪在了下面這個test case:

2
["0:start:0","0:start:2","0:end:5","1:start:7","1:end:7","0:end:8"]

Expected:
[8,1]

這個結果很confusing啊,你想啊,函式0運行了時間點0,1,2,3,4,5,8,共7秒,函式1運行了時間點7,共1秒,為啥答案不是[7,1]而是[8,1]呢?

根據分析網上大神們的解法,貌似時間點6還是函式0在執行。這是為啥呢,說明博主之前的理解有誤,當函式0在時間點2時再次開啟時,前面那個函式0應該沒有被強制關閉,所以現在實際上有兩個函式0在執行,所以當我們在時間點5關掉一個函式0時,還有另一個函式0在跑,所以時間點6還是函式0的,還得給函式0續1秒。這樣才能解釋的通這個case啊。這樣的話用棧stack就比較合適了,函式開啟了就壓入棧,結束了就出棧,不會有函式被漏掉。這樣的我們可以遍歷每個log,然後把三部分分開,函式idx,型別type,時間點time。如果此時棧不空,說明之前肯定有函式在跑,那麼不管當前時start還是end,之前函式時間都得增加,增加的值為time - preTime,這裡的preTime是上一個時間點。然後我們更新preTime為當前時間點time。然後我們判斷log的型別,如果是start,我們將當前函式壓入棧;如果是end,那麼我們將棧頂元素取出,對其加1秒,並且preTime也要加1秒,參見程式碼如下:

解法一:

class Solution {
public:
    vector<int> exclusiveTime(int n, vector<string>& logs) {
        vector<int> res(n, 0);
        stack<int> st;
        int preTime = 0;
        for (string log : logs) {
            int found1 = log.find(":");
            int found2 = log.find_last_of(":");
            int idx = stoi(log.substr(0, found1));
            string type = log.substr(found1 + 1, found2 - found1 - 1);
            int time = stoi(log.substr(found2 + 1));
            if (!st.empty()) {
                res[st.top()] += time - preTime;
            }
            preTime = time;
            if (type == "start") st.push(idx);
            else {
                auto t = st.top(); st.pop();
                ++res[t];
                ++preTime;
            }
        }
        return res;
    }
};

下面這種方法比較叼的地方是在於使用了C語言的sscanf函式來一步讀取了三個變數,注意這裡面的"[^:]",表示copy所有字元,直到遇到':',這樣就能把中間的start或者end拷到type中去了。而且接下來的寫法跟上面也不太相同,這裡先判斷了type的型別,如果是start,那麼再看如果棧不為空,那麼棧頂函式加上時間差,這個上面講過了,然後將當前函式壓入棧;如果是end,那麼棧頂元素加上時間差,還要再加1秒,這個在上面也提到了加了1秒的事,然後再將棧頂元素出棧。最後更新preTime為當前時間點。講解中加了這麼多秒,博主已經盡力了。。。

解法二:

class Solution {
public:
    vector<int> exclusiveTime(int n, vector<string>& logs) {
        vector<int> res(n, 0);
        stack<int> st;
        int preTime = 0, idx = 0, time = 0;
        char type[10];
        for (string log : logs) {
            sscanf(log.c_str(), "%d:%[^:]:%d", &idx, type, &time);
            if (type[0] == 's') {
                if (!st.empty()) {
                    res[st.top()] += time - preTime;
                }
                st.push(idx);
            } else {
                res[st.top()] += ++time - preTime;
                st.pop();
            }
            preTime = time;
        }
        return res;
    }
};

參考資料: