首先,这是一篇马后炮。这题在面试过程当中,面试官首先提到了操做系统,多线程操做什么的。而后如今给定线程只有一个,任务有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
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这个,这么看好像这题跑不出别的思路了。总之是很是遗憾。
另外也总结出一个教训,就是千万别给面试官直接喷你的机会,面试官真的啥人都有,哪怕是和你同龄的中国人,也是脑子有些问题,直接说背景不行,致使本身心态不稳,发挥严重失常。下回仍是保持日常心,而后别想太多吧。这一篇文字比较正经,也是想借这个机会来面对一下本身失败的经历吧。线程