这道面试题是从 HarrisonHao 的一篇博文中看到的:原文链接

我看到之后,感觉此题十分有趣,遂自己用 node.js 以不同的思路实现了一遍,实现中使用了 lodash

原题比较长,而且是英文的,就不粘过来了,完整题目和代码可见github

原题大意

你正在准备一场大型的开发者会议,但是有一点点麻烦……

这场会议为期两天,每天上午从九点开始,上午的会议安排到中午12点之前必须结束;

中午12点到下午1点之间是午餐时间,下午1点开始进行下午的会议,到下午5点前必须结束;

现在你有一个清单,上面写明了所有要安排的议题,和每个议题会占用的时间;

清单如下

Writing Fast Tests Against Enterprise Rails 60min

Overdoing it in Python 45min

Lua for the Masses 30min

Ruby Errors from Mismatched Gem Versions 45min

Common Ruby Errors 45min

Rails for Python Developers lightning

Communicating Over Distance 60min

Accounting-Driven Development 45min

Woah 30min

Sit Down and Write 30min

Pair Programming vs Noise 45min

Rails Magic 60min

Ruby on Rails: Why We Should Move On 60min

Clojure Ate Scala (on my project) 45min

Programming in the Boondocks of Seattle 30min

Ruby vs. Clojure for Back-End Development 30min

Ruby on Rails Legacy App Maintenance 60min

A World Without HackerNews 30min

User Interface CSS in Rails Apps 30min

清单中lightning占用5分钟,其他议题都各自注明了占用时间

现在你要写一个程序把清单上的议题安排进四个时间段内。

用 HarrisonHao 的话说,就是要把19个给定大小的萝卜放进4个给定大小的坑里,坑可以没占满,但萝卜不能剩下。

基本的实现思路

先把清单中的议题按照占用时间排序,方便后续操作,然后开始往时间段中安排,每次拿出一个最耗时的议题,放入最空闲的时段中,不断循环,直到所有议题都被安排进去;

首先,我们先看看有哪些萝卜(读取清单并排序)

本次是在 node.js 中实现的,使用 fs 模块读取文件,按行分割后,将每行内容转为一个 Talk 对象,并按占用时间进行排序:

const fs = require('fs');
const _ = require('lodash'); //会议类
class Talk {
constructor (line) {
const words = _.compact(line.split(' '));
const duration = words.pop();
if (isNaN(duration[0])) {
words.push(duration)
this.duration = 5;
} else {
this.duration = duration.slice(0, -4);
}
this.name= words.join(' ')
}
}
//获得输入参数
const args = process.argv.splice(2);
const [inputPath, outputPath] = args; //读取输入文件内容
let input = fs.readFileSync(inputPath, 'utf8')
//分割输入文件内容
input = _.compact(input.split('\r').join().split('\n')); //生成会议列表
let talks = input.map(line=>new Talk(line));
//按占用时间从小到大排序
talks = _.orderBy(talks, 'duration');

然后我们来看看有哪几个坑……(生成时间段)

Slot 类实例化时接收一个总可用分钟数,并包含三个方法:

add: 将一个议题添加进该时间段,

used: 返回已使用的分钟数,

balance: 返回空闲的分钟数

每天上午有3个小时会议时间即180分钟,下午240分钟,所以我们可以直接用这两个分钟数来生成时间段:

//时间段类
class Slot {
constructor (limit) {
this.limit = limit;
this.list = [];
};
//剩余可用分钟数
balance () {
return this.limit - this.used()
};
//已安排掉的分钟数
used () {
let used = 0;
this.list.forEach((talk)=>{
used += (talk.duration-0)
});
return used;
};
add (talk) {
this.list.push(talk)
}
} //生成时间段列表
let slots = [180, 240, 180, 240].map(limit=>new Slot(limit));

核心部分

现在要把萝卜往坑里扔了,之前提到思路是每次把耗时最长的议题扔进最空闲的时间段中,不断循环,直到所有议题(萝卜)都安排进时间段(坑)里;

获取耗时最长的议题很简单,因为我们之前已经给议题排序了,每次只要.pop()弹出最后一条议题就可以了;

获取最空闲的时间段也是一样的原理,用上 Slot 对象的 balance 方法,按照空闲时间倒序排序,排序结果的第一条就是最空闲的时间段;

具体实现:


//分配会议
function arrange (talks, slots) {
//拿出一个占用时间最长的会议
const talk = talks.pop();
//放到时间最富裕的时间段内
slots = _.orderBy(slots, slot=>slot.balance(), 'desc');
slots[0].add(talk);
if (talks.length == 0) return slots;
return arrange(talks, slots);
}; //分配每个会议到各个时间段内
const result = arrange(talks, slots);

格式化输出

反正原题似乎是要求按一定格式输出的……不过格式这种东西就不细说了,上个代码得了……

//格式化输出
function print (slots) {
const formatNum = (num)=>('0'+num).slice(-2); const am = {}, pm = {}; [am[1],am[2],pm[1],pm[2]] = _.orderBy(slots, 'limit'); [1,2].forEach((i)=>{
let minutes;
console.log('Track '+i);
minutes = 9*60
am[i].list.forEach((talk)=>{
const h = formatNum(Math.floor(minutes/60));
const m = formatNum(minutes%60);
const outputLine = [
h,':',m,'AM',' ',
talk.name,' ',talk.duration,'min'
].join('');
console.log(outputLine);
minutes += talk.duration-0;
})
console.log('12:00PM Lunch');
minutes = 1*60
pm[i].list.forEach((talk)=>{
const h = formatNum(parseInt(minutes/60));
const m = formatNum(minutes%60);
const outputLine = [
h,':',m,'PM',' ',
talk.name,' ',talk.duration,'min'
].join('');
console.log(outputLine);
minutes += talk.duration-0;
})
console.log('05:00PM Networking Event');
})
} print(slots);

最终效果

λ node conference.js input.txt
Track 1
09:00AM Clojure Ate Scala (on my project) 45min
09:45AM Pair Programming vs Noise 45min
10:30AM Overdoing it in Python 45min
11:15AM Lua for the Masses 30min
11:45AM Rails for Python Developers lightning, 5min
12:00PM Lunch
01:00PM Ruby on Rails: Why We Should Move On 60min
02:00PM Rails Magic 60min
03:00PM Ruby Errors from Mismatched Gem Versions 45min
03:45PM User Interface CSS in Rails Apps 30min
04:15PM Woah 30min
05:00PM Networking Event
Track 2
09:00AM Writing Fast Tests Against Enterprise Rails 60min
10:00AM Accounting-Driven Development 45min
10:45AM Ruby vs. Clojure for Back-End Development 30min
11:15AM Programming in the Boondocks of Seattle 30min
12:00PM Lunch
01:00PM Ruby on Rails Legacy App Maintenance 60min
02:00PM Communicating Over Distance 60min
03:00PM Common Ruby Errors 45min
03:45PM A World Without HackerNews 30min
04:15PM Sit Down and Write 30min
05:00PM Networking Event

总结

虽然是实现了效果,但我感觉还不完善,现在这种算法还很简单,原题本身就富裕了55分钟的时间,所以才能用这种方式实现,如果占的更满就不一定好使了,以后我会再继续尝试改进;

如果有更好的思路也欢迎告诉我,我也会试着实现一下的~

使用javascript解一道关于会议日程安排的面试题的更多相关文章

  1. dhtmlxScheduler日程安排控件

    dhtmlxScheduler是一个JavaScript日程安排控件 官方网站:http://www.dhtmlx.com/在线帮助文档:http://docs.dhtmlx.com/doku.php ...

  2. Conference Search不错的学术会议日程提示网站

    一个不错的学术会议日程提示网站 http://www.confsearch.org,还可以通过内嵌框架(embedded iframe)集成到自己的网页上. http://www.confsearch ...

  3. Visio日程安排图

    黄日历: 怎么创建呢? 首先找到日程安排图表 然后找到日历 这就是日历的形状模块 拖动“日”日历形状进行创建 创建好的日历通过右键单击选择"配置"来修改日期 这是周日历 与日日历不 ...

  4. JavaScript解构赋值

    JavaScript解构赋值 JavaScript解构赋值为我们提供了很多方便,但是用法比较多,本文就来梳理一下.总体来说,主要就两种地方使用解构赋值,一种是数组的解构赋值,另一种是对象的解构赋值.以 ...

  5. 一款很好的日程安排插件fullcalendar 非常适合OA等系统

    1.插件下载 http://arshaw.com/fullcalendar/download/ 2. <!DOCTYPE html> <meta http-equiv="C ...

  6. JS实现日程安排 日程安排插件

    代码: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="EmpWeekPla ...

  7. Javascript 解构的用处

    对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量. let { log, sin, cos } = Math; 上面代码将Math对象的对数.正弦.余弦三个方法,赋值到对应的变量上,使用起 ...

  8. 同步Windows 10与MIUI 9来完成你的日程安排

    我们都知道,outlook可以有效管理你的日程.而MIUI 9在负一屏上全新改版了界面,变得更加全面人性化.接下来我将展示几种方法,让你的Windows 10与MIUI 9协同工作. 一.outloo ...

  9. 算法是什么我记不住,But i do it my way. 解一道滴滴出行秋招编程题。

    只因在今日头条刷到一篇文章,我就这样伤害我自己,手贱. 刷头条看到一篇文章写的滴滴出行2017秋招编程题,后来发现原文在这里http://www.cnblogs.com/SHERO-Vae/p/588 ...

随机推荐

  1. API网关Ocelot 使用Polly 处理部分失败问题

    在实现API Gateway过程中,另外一个需要考虑的问题就是部分失败.这个问题发生在分布式系统中当一个服务调用另外一个服务超时或者不可用的情况.API Gateway不应该被阻断并处于无限期等待下游 ...

  2. WebServerice

    WebServerice是什么 web service是一个web应用程序的分支,是构建应用程序的普通模型,可以在支持Internet网络通信操作系统上实施. 它的原理主要是利用HTTP协议使数据在w ...

  3. Redis 学习之事务处理

    Redis事务机制 在MySQL等其他数据库中,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行. Redis目前对事物的支持相对简单.Redis只能保证一个client发起的事务中的命令可 ...

  4. android学习3——长宽的单位问题dp,px,dpi

    android设备的单位px,pt,dp,sp 分辨率 先通俗说下分辨率的概念.可以把屏幕想想成一个个正方形格子组成的.如果横向有1280个格子,竖向有720个格子.那么分辨率就是1280*720.这 ...

  5. UU农场平台开发 UU农场拆复利系统

    UU农场平台开发 UU农场拆复利系统今年比较新的一款游戏,类似于QQ农场,但又加入了很多新型的互联网理财模式!UU农场平台开发 UU农场拆复利系统.UU农场开发.UU农场游戏平台开发.UU农场平台开发 ...

  6. 关于NoClassDefFoundError和ClassNotFoundException异常

    java.lang.NoClassDefFoundError 和 java.lang.ClassNotFoundException 都是 Java 语言定义的标准异常.从异常类的名称看似乎都跟类的定义 ...

  7. 基于keepalived搭建MySQL高可用集群

    MySQL的高可用方案一般有如下几种: keepalived+双主,MHA,MMM,Heartbeat+DRBD,PXC,Galera Cluster 比较常用的是keepalived+双主,MHA和 ...

  8. SUN SERVER X3-2 服务器数据写入缓慢

    使用一台sun server x3-2,SAS 300G 2.5寸硬盘两块:8G内存条*2,CPU E5-2609V3 安装一套服务器系统时感觉安装进度很慢,但一直找不到原因,因为要重做系统,同事练手 ...

  9. web前端的发展态势 浅识

    以前 作为一个java程序员写的代码主要还是后台的代码,虽然开始的时候前后端都写,但是也是用别人造好的轮子来用,学学html,css,js,jquery,再找一个前端ui框架学学,上手之后我们就可以写 ...

  10. 如何快速的学习selenium工具

    分享即快乐. 最近几年,软件测试工程师一度成为热门职业,作为测试员也是倍感压力.作为测试员来说,仅仅会手工测试让职业生涯陷入瓶颈.于是工作之余充电,学习了自动化测试工具selenium,打算进阶中高级 ...