资讯专栏INFORMATION COLUMN

【Snapchat 电面面经】多任务单线程时间打印Parse Log

sf190404 / 1174人阅读

摘要:给出了这个例子还给出了实际情况中,这种多线程可能出现的场景。文章的发布时间应该是有记录的,那么至少现在这个时候我还基本处于完全不懂操作系统的状态,多线程也只是的看了几个视频。

题目内容

首先,这是一篇马后炮。这题在面试过程中,面试官首先提到了操作系统,多线程操作什么的。然后现在给定线程只有一个,任务有f1,f2.。。可能多个,打出各个任务执行的时间。
给出了这个例子:

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来做,每次任务来的时候,判断当前要执行的任务,打断了之前的哪些任务。同时做的时候发现需要一个变量来记录上一次有任务变更的时间。背后的原理总感觉只隔了一层纸,但是现在只能按照刷题的思路去解决它。

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 files){
        // 注意了,我开始注意命名规则了,这个map是为了最后输出用。
        Map> fileMap = new HashMap<>();
        // 我当时还是现查的Long类型需要加个L。
        Long prevTime = 0L;
        Stack 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 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 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 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 infos = Arrays.asList(infoArr);
        test.parseLog(infos);
    }
}
复杂度分析

这个其实没啥要分析复杂度的,就是跑一遍。把输出算上,也就是O(n)。

最后再说两句

这道题是面经,准备了23道题,做了22道,唯一一道没做的题目,结果就被命中了。准备不足是这次电面挂掉的主要原因。实力其实是足够的,在没有操作系统的基础知识,加上只给了20分钟不到的情况下,思路几乎完全正确,除了忘了加prevTime这个,这么看好像这题跑不出别的思路了。总之是非常遗憾。
另外也总结出一个教训,就是千万别给面试官直接喷你的机会,面试官真的啥人都有,哪怕是和你同龄的中国人,也是脑子有些问题,直接说背景不行,导致自己心态不稳,发挥严重失常。下回还是保持平常心,然后别想太多吧。这一篇文字比较正经,也是想借这个机会来面对一下自己失败的经历吧。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/65229.html

相关文章

  • 18年求职面经及总结

    摘要:年求职面经及总结我的求职之路差不多走到尽头了感觉真是精疲力尽了把这大半年的经历和面试总结写下来希望能给和我一样在求职路上煎熬的人一点帮助先说背景微电子科学与工程专业学过两门和相关的课程语言和单片机这个专业的唯一好处就是大部分人并不知道这个专 18年求职面经及总结 我的求职之路差不多走到尽头了,感觉真是精疲力尽了.把这大半年的经历和面试总结写下来,希望能给和我一样在求职路上煎熬的人一点帮...

    zhangwang 评论0 收藏0
  • 18年求职面经及总结

    摘要:年求职面经及总结我的求职之路差不多走到尽头了感觉真是精疲力尽了把这大半年的经历和面试总结写下来希望能给和我一样在求职路上煎熬的人一点帮助先说背景微电子科学与工程专业学过两门和相关的课程语言和单片机这个专业的唯一好处就是大部分人并不知道这个专 18年求职面经及总结 我的求职之路差不多走到尽头了,感觉真是精疲力尽了.把这大半年的经历和面试总结写下来,希望能给和我一样在求职路上煎熬的人一点帮...

    fjcgreat 评论0 收藏0
  • JavaScript疑难杂症系列-事件循环

    摘要:而之后事件循环一直会去遍历任务队列,一旦有任务放入就会放入主线程中执行。任务队列所谓任务是返回的一个个通知,让主线程在读取任务队列的时候得知这个异步任务已经完成,下一步该执行这个任务的回调函数了。 javascript单线程 浏览器端,复杂的UI环境会限制多线程语言的开发。例如,一个线程在操作一个DOM元素时,另一个线程需要去删除DOM元素,这个之间就需要进行状态的同步,何况前端可能不...

    Keagan 评论0 收藏0

发表评论

0条评论

sf190404

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<