【Snapchat 電面面經】多任務單線程時間打印Parse Log

題目內容

首先,這是一篇馬後炮。這題在面試過程當中,面試官首先提到了操做系統,多線程操做什麼的。而後如今給定線程只有一個,任務有f1,f2.。。可能多個,打出各個任務執行的時間。
給出了這個例子:java

input:
funcName, isStart, timestamp(long)
f1 start 1
f2 start 3
f1 start 7
f1 end 8
f2 end 13
f1 end 22

output:
f1 : [[1, 3],[7,8], [13,22]]
f2 : [[3, 7], [8,13]]

還給出了實際狀況中,這種多線程可能出現的場景。好比這樣:面試

void f1() {
    // record the func start time
    if (some_condition) {
        f2();
    }
    // record the func end time
}

void f2() {
    // record the func start time
    if (some_condition) {
        f1();
    }
    // record the func end time
}

main() {
    f1();
}

而後要求是寫個function,給定了輸入,把輸出弄出來。多線程

解決思路

這題其實背後應該有操做系統的基礎知識支撐。文章的發佈時間應該是有記錄的,那麼至少如今這個時候我還基本處於徹底不懂操做系統的狀態,多線程也只是Java的看了幾個視頻。既然是馬後炮,直接給出個人解決想法,就是用stack來作,每次任務來的時候,判斷當前要執行的任務,打斷了以前的哪些任務。同時作的時候發現須要一個變量來記錄上一次有任務變動的時間。背後的原理總感受只隔了一層紙,可是如今只能按照刷題的思路去解決它。this

code

import java.util.*;
//首先建一個File類,表示任務,id表示它的名字。
class File {
    String id;
    Boolean isStart;
    Long timestamp;
    public File(String name, Boolean isStart, Long timestamp){
        id = name;
        this.isStart = isStart;
        this.timestamp = timestamp;
    }
}
// Slot類表示時間區間。
class Slot {
    Long start;
    Long end;
    public Slot(Long start, Long end){
        this.start = start;
        this.end = end;
    }
}
// stack裏面,要麼是f2進來,裏面f1在跑,要麼是f2進來,裏面f2在跑。這個分配必需要思考清楚。
// 補充一個,f2進來,f2在跑的狀況,中間是會被打斷的,好比f2-f1-f1-f2,因此要記錄一個prevTime,由於最開始f2帶的timestamp沒用了。
class ParseLog{
    public void parseLog(List<File> files){
        // 注意了,我開始注意命名規則了,這個map是爲了最後輸出用。
        Map<String, List<Slot>> fileMap = new HashMap<>();
        // 我當時仍是現查的Long類型須要加個L。
        Long prevTime = 0L;
        Stack<File> fileStack = new Stack<>();
        // 從這裏開搞,每次拿一個file進去。
        for (int i = 0; i < files.size(); i++) {
            File curF = files.get(i);
            // 空stack那就往裏壓。
            if (fileStack.isEmpty()) {
                fileStack.push(curF);
            }
            else {
                // 先把stack頂的file命名一下,後面方便辦事。
                File topF = fileStack.peek();
                // 這種就是f2進來,發現上面也是個f2
                if (curF.id.equals(topF.id)) {
                    // 這時候f2必須是帶着結束屬性來的。
                    if (!curF.isStart) {
                        Long endTs = curF.timestamp;
                        List<Slot> temp = new ArrayList<>();
                        if (fileMap.containsKey(curF.id)) {
                            temp = fileMap.get(curF.id);
                        }
                        // 這時候,prevTime的做用就顯示出來了。
                        temp.add(new Slot(prevTime, endTs));
                        fileMap.put(curF.id, temp);
                        // 上面是標準的添加到map的過程,而後把f2起始的那個file從stack裏面刪掉。
                        fileStack.pop();
                    }
                    else {
                        // 這種就是非法狀況,那就報錯吧。
                        System.out.println("this task has already started");
                    }
                }
                else {
                    // 這裏面是f2進來,上一步執行的是f1這種狀況。
                    if (curF.isStart) {
                        Long endTs = curF.timestamp;
                        // 這時候須要停掉的是f1,也就是stack頂部的file,由於只有單線程。
                        List<Slot> temp = new ArrayList<>();
                        if (fileMap.containsKey(topF.id)) {
                            temp = fileMap.get(topF.id);
                        }
                        temp.add(new Slot(prevTime, endTs));
                        fileMap.put(topF.id, temp);
                        // 帶着開始屬性的file必須壓入。
                        fileStack.push(curF);
                    }
                    else {
                        System.out.println("this task hasn't started yet");
                    }
                }
            }
            // 這裏很是關鍵,就是每次讀完一個file以後,都要更新這個時間。
            prevTime = curF.timestamp;
        }
        // 這裏就是擺弄好輸出就行。
        for(String str : fileMap.keySet()){
            System.out.print(str + " : ");
            List<Slot> list = fileMap.get(str);
            for (Slot s : list) {
                System.out.print("[ " + s.start + " " + s.end + " ] ");
            }
            System.out.println();
        }
    }
    public static void main(String args[]){
        ParseLog test = new ParseLog();
        File f1 = new File("f1", true, 1L);
        File f2 = new File("f2", true, 3L);
        File f3 = new File("f1", true, 7L);
        File f4 = new File("f1", false, 8L);
        File f5 = new File("f2", false, 13L);
        File f6 = new File("f1", false, 22L);

        File[] infoArr = {f1, f2, f3, f4,f5, f6};
        List<File> infos = Arrays.asList(infoArr);
        test.parseLog(infos);
    }
}

複雜度分析

這個其實沒啥要分析複雜度的,就是跑一遍。把輸出算上,也就是O(n)。操作系統

最後再說兩句

這道題是面經,準備了23道題,作了22道,惟一一道沒作的題目,結果就被命中了。準備不足是此次電面掛掉的主要緣由。實力實際上是足夠的,在沒有操做系統的基礎知識,加上只給了20分鐘不到的狀況下,思路幾乎徹底正確,除了忘了加prevTime這個,這麼看好像這題跑不出別的思路了。總之是很是遺憾。
另外也總結出一個教訓,就是千萬別給面試官直接噴你的機會,面試官真的啥人都有,哪怕是和你同齡的中國人,也是腦子有些問題,直接說背景不行,致使本身心態不穩,發揮嚴重失常。下回仍是保持日常心,而後別想太多吧。這一篇文字比較正經,也是想借這個機會來面對一下本身失敗的經歷吧。線程

相關文章
相關標籤/搜索