编程冠军:为前端开发人员解析任务

前几天,编程冠军的优胜者于初夏结束,获得了当之无愧的奖项。 为此,我们打电话给他们,以及从每个方向的前20名到Yandex莫斯科办公室的所有其他决赛入围者。 再次祝贺那些成功进入决赛的人。

同时,我们准备了有关向前端开发人员提供的冠军任务的讨论。 这些是资格鉴定阶段的任务。 我们提醒您,冠军赛在四个领域举行:后端,前端,机器学习和分析。

A.温度计


条件


使用导航仪,许多人在构建汽车路线时看到了“温度计”。 它是多色的直线,表示路线上的道路拥堵。 在此任务中,建议编写一个函数以针对不同的屏幕尺寸适应“温度计”的数据。

功能输入具有长度length和屏幕尺寸widthlength ≥ width )的颜色数组,温度计将在其上显示。 所使用的GREENYELLOWRED对应于低,中和高负载。 颜色在流量方面具有可比性: GREEN < YELLOW < RED

从第一个元素开始,初始数组被分成连续的不相交的子数组,它们的长度为length / width (数字始终为整数)。 在每个子阵列中,有必要根据道路拥堵程度的增加来排列颜色,选择中间颜色并用其替换整个颜色。 对于偶数长度的数组,选择“较低的中位数”(在n元素的有序行中,元素n/2 )。 结果应该是长度为width的颜色数组。

该解决方案必须作为CommonJS模块提供:

 module.exports = function (segments, width) { // Your code here. }; 

RE裁决还意味着提交的解决方案不正确。

其他选项
进入结论
 const segments = ['GREEN', 'GREEN', 'RED', 'GREEN', 'YELLOW', 'RED', 'GREEN', 'YELLOW', 'RED', 'YELLOW']; const width = 5; 
['GREEN', 'GREEN', 'YELLOW', 'GREEN', 'YELLOW']

解决方案


1.将片段的初始数组分成length / width片段。
2.在每个段中,根据条件选择中间颜色,然后将找到的颜色添加到结果数组中。

solution.js
 module.exports = function solution(segments, width) { const blockSize = segments.length / width; const result = []; for (let i = 0; i < width; i++) { result.push(getMedian(segments.slice(i * blockSize, (i + 1) * blockSize))); } return result; }; function getMedian(array) { const map = { GREEN: 1, YELLOW: 2, RED: 3 }; return array.sort((a, b) => map[a] - map[b])[Math.floor((array.length - 1) / 2)]; } 

B.洪流客户


条件


您决定编写洪流客户端。 它的特征是在它的帮助下,仅可以传输文本。

torrent客户端几乎已准备就绪,最重要的仍然是:从将其分割成小段进行传输的片段中收集源文本。

编写一个函数,等待所有文本加载并从中收集源代码。

该函数接受具有两个字段的对象: chunkCountemitter ,并以指定格式的字符串形式返回包含源文本或错误的promise。

chunkCount文本被分割成的片段数。

每段文本都有一个唯一的标识符和发送时间。 发送时间较晚的片段离文本开头更远。

emitter -一个可以下载文本的对象。 文本片段可能会随时间延迟到达。 件的顺序可以是任何顺序。

如果在成功完成下载之前两次收到相同的文本,则该函数应引发"Duplicate: <id>"错误(用文本的<id>代替<id> )。

收到所有文本后,有必要将它们合并为一行,并使用promise返回此行。 如果两个片段具有相同的发送时间,则这些片段在返回的字符串中的顺序可以是任意的。

如果传输在一秒钟内未完成,则该函数应引发"Timed out"错误。

输入对应于TypeScript上的此类接口
(TS接口的一般说明 。)

 interface Input { chunkCount: number; emitter: Emitter; } interface Emitter { on: (callback: (chunk: Chunk) => void) => void; } interface Chunk { id: number; timestamp: Date; data: string; } 


该解决方案必须作为CommonJS模块提供:

 module.exports = function ({chunkCount, emitter}) { //  Promise }; 

RE裁决还意味着提交的解决方案不正确。

其他选项
例子
进入结论
 { chunkCount: 3, emitter: {on: (fn) => { fn({id: 5314, data: 'The Good, ', timestamp: new Date('2019-01-01')}); fn({id: 1543, data: 'd the Ugly', timestamp: new Date('2019-01-03')}); fn({id: 2494, data: 'the Bad an', timestamp: new Date('2019-01-02')}); }} } 
Resolved with "The Good, the Bad and the Ugly"
 { chunkCount: 1, emitter: {on: (fn) => { fn({id: 0, data: 'hello', timestamp: new Date('2019-01-01')}); fn({id: 0, data: 'world', timestamp: new Date('2019-01-02')}); }} } 
Rejected with "Duplicate id: 0"
 { chunkCount: 2, emitter: {on: (fn) => {}} } 
Rejected with "Timed out"

解决方案


  • 将加载的块保存到chunk对象。
  • 同时,我们检查id的存在。 如果已经存在,则取消承诺。
  • 装入所有部件后,将它们分类并合并。
  • 与此同时,您需要将超时设置为1秒。


solution.js
 module.exports = function ({chunkCount, emitter: {on}}) { return new Promise((resolve, reject) => { const chunks = {}; let chunksDownloaded = 0; on(({id, data, timestamp}) => { if (typeof chunks[id] !== 'undefined') { reject(`Duplicate: ${id}`); } else { chunks[id] = {data, timestamp}; chunksDownloaded += 1; if (chunksDownloaded === chunkCount) { const result = Object.values(chunks) .sort((a, b) => a.timestamp - b.timestamp) .map(({data}) => data) .join(''); resolve(result); } } }); setTimeout(() => { reject('Timed out'); }, 1000); }); }; 

C.二叉树


条件


开发人员Grisha被赋予实施二叉树的任务,但是他对本质的理解很差,并且犯了许多错误。 帮助他找到并修复它们。

必须找到并修复task.js代码中的错误。 必须导出一个类才能使用二叉树。 类接口:

 type Data = number; type ITraverseCallback = (data: Data) => void; interface IBinaryTreeNode { data: Data; left: IBinaryTreeNode | null; right: IBinaryTreeNode | null; static create(...items: Data[]): IBinaryTreeNode; constructor(data: Data); insert(data: Data): this; remove(data: Data): IBinaryTreeNode | null; search(data: Data): IBinaryTreeNode | null; inorder(callback: ITraverseCallback): this; preorder(callback: ITraverseCallback): this; postorder(callback: ITraverseCallback): this; } 

注意 :认为JSDoc是正确的。

RE裁决还意味着提交的解决方案不正确。

其他选项
输入示例
 let output = ''; BinaryTreeNode.create(10, 5, 13, 7, 20, 12).inorder((data) => { output += data + '-'; }); 

结论
 5-7-10-12-13-20- 

解决方案


 /** * @typedef Data * @type {Number} */ class BinaryTreeNode { /** * @param {...Data} items * @returns {BinaryTreeNode} */ static create(...items) { // e - . const root = new BinaryTreeNode(items[0]); //  return   . //  .slice(1),     . return items.slice(1).reduce((node, data) => node.insert(data), root); } /** * @param {Data} data */ constructor(data) { /** * @type {Data} */ this.data = data; //    . /** * @type {BinaryTreeNode | null} */ this.left = null; /** * @type {BinaryTreeNode | null} */ this.right = null; } /** *    . *    ,      . * * @param {Date} data * @returns {BinaryTreeNode} */ insert(data) { //    . if (data < this.data) { if (this.left === null) { this.left = new BinaryTreeNode(data); } else { this.left.insert(data); } } else { if (this.right === null) { this.right = new BinaryTreeNode(data); } else { this.right.insert(data); } } //    ,   . return this; } /** *     . *   ,   . * * @param {Data} data * @returns {BinaryTreeNode | null} */ remove(data) { //     {}. //    . if (data < this.data) { //     `this.left`. this.left = this.left && this.left.remove(data); } else if (data > this.data) { //     `this.right`. this.right = this.right && this.right.remove(data); } else { if (this.left === null && this.right === null) { return null; } if (this.left === null) { return this.right; } else if (this.right === null) { return this.left; } const aux = findMinNode(this.right); this.data = aux.data; this.right = this.right.remove(aux.data); } //    ,   . return this; } /** *     . * * @param {Data} data * @returns {BinaryTreeNode | null} */ search(data) { //    . if (data < this.data) { //     `this.left`. return this.left && this.left.search(data); } if (data > this.data) { //     `this.right`. return this.right && this.right.search(data); } //  ,     ,    `null`. if (data === this.data) { return this; } return null; } /** *    ,           . *     . * * @param {Function} callback * @returns {BinaryTreeNode} */ inorder(callback) { if (this.left !== null) { this.left.inorder(callback); } callback(this.data); if (this.right !== null) { this.right.inorder(callback); } //    ,   . return this; } /** *   ,           . * * @param {Function} callback * @returns {BinaryTreeNode} */ preorder(callback) { callback(this.data); if (this.left !== null) { //       . this.left.preorder(callback); } if (this.right !== null) { this.right.preorder(callback); } //    ,   . return this; } /** *   ,            . * * @param {Function} callback * @returns {BinaryTreeNode} */ postorder(callback) { if (this.left !== null) { this.left.postorder(callback); } if (this.right !== null) { //       . this.right.postorder(callback); } //   ,     . callback(this.data); return this; } } /** *   ,   . * * @param {BinaryTreeNode} node * @returns {BinaryTreeNode} */ function findMinNode(node) { //       . //    true  false. if (node.left === null) { return node; } else { return findMinNode(node.left); } } module.exports = BinaryTreeNode; 

D.Yandex.Maps徽标


条件


设计者更新了Yandex.Maps徽标(x5比例尺):



它需要在各种条件下使用。 为了使它尽可能方便,请在纯CSS中用一个HTML元素组成它。 徽标可以在界面的任何位置使用,因此正确显示在任何背景上非常重要。

您无法使用图片(即使通过data:uri )。

其他选项

-中心圆圈颜色:#fff
-外圈的颜色:#f33
-“腿”的颜色:#e00000

解决方案必须作为CSS文件提供。 您的文件将作为solution.css连接到以下形式的HTML页面:

 <!DOCTYPE html> <html> <head> <style> body { margin: 0; } </style> <link rel="stylesheet" href="solution.css"> </head> <body> <div></div> </body> </html> 

重要提示 :徽标应位于页面的左上角,并紧紧按在其上。

您的解决方案将在Google Chrome 69浏览器中进行测试。

我们建议对完美像素布局使用插件,例如PerfectPixel

解决方案


 //          . div { position: absolute; width: 6px; height: 6px; border: 5px solid #f33; border-radius: 8px; background: #fff; } //     «» . //    ,      9 . div::after { content: ''; position: absolute; top: 6px; left: 2px; border-top: 15px solid #e00000; border-right: 7px solid transparent; transform: rotate(9deg); z-index: -1; } 


E.砖网


条件


开发人员Ivan决定重构页面的CSS样式,此后他破坏了页面的外观。

初始设计:

您需要使外观与原始设计保持一致,并且当前CSS文件中的更改次数最少。

重要说明 :将项目添加到列表中时,网格应类似地向下扩展。

重构后的CSS样式: ./solution.css

更正后,您需要提供更新的CSS文件。 该文件将作为固定solution.css连接到HTML页面

其他选项
您的解决方案将在Google Chrome 69浏览器中进行测试。 字体系列和其他字体设置不需要更改。 在这种情况下,字体在本地可能与预期状态不匹配,因为屏幕截图是在Ubuntu中拍摄的。

我们建议对完美像素布局使用插件,例如PerfectPixel

解决方案


只能使用.event选择器及其后代进行更改。

 :root { --color-gray: #4e4d4d; --color-main: #000000; --width-layout: 900px; --paddingx5: 50px; --paddingx4: 40px; --paddingx3: 30px; --paddingx2: 20px; --padding: 10px; --font-size-largex2: 40px; --font-size-large: 20px; --font-size-medium: 16px; --font-size-small: 14px; } body { margin: 0 auto; padding: var(--paddingx5) var(--paddingx4); font: var(--font-size-small)/1.4 arialregular; color: var(--color-main); width: var(--width-layout); } .hgroup { margin-bottom: var(--paddingx4); text-align: center; } .hgroup__title { font-size: var(--font-size-largex2); font-weight: normal; margin: 0; } .hgroup__desc { font-size: var(--font-size-large); font-weight: normal; color: var(--color-gray); margin: 0; } .events { list-style: none; margin: 0; padding: 0; //    . //      . columns: 3; column-gap: var(--paddingx4); } .events__item { //    . break-inside: avoid; //  margin     . padding-bottom: var(--paddingx4); } .card { text-decoration: none; color: var(--color-main); display: block; } .card:hover .card__title { text-decoration: underline; } .card__image { width: 100%; display: block; height: 100px; background: var(--color-gray); margin-bottom: var(--padding); } .card__title { margin: 0 0 var(--padding); } .card__summary { margin: 0; color: var(--color-gray); } 

F.乘坐地铁


条件


有Devopia Petya。 在工作中,他需要在接下来的100天中的某些天当值。 佩蒂亚乘坐地铁去上班。 引入了地铁票,该票自第一次旅行起就在一定天数内有效。 票证的有效期越长,每天的费用就越低。 有必要帮助Petya省钱,并考虑到他的工作时间表,提前三个月计算出他需要购买的机票,以使总费用尽可能低。 而且Petya不喜欢随身携带许多票,并且如果有几种票务选项具有相同的最低费用,则Petya需要一种票数更少的票。 如果有多个这样的选择(具有相同的最低费用和票数),则Pete将适合其中的任何一个。

您需要编写一个功能getCheapestTickets(days, tickets) ,该函数将Petya的工作时间表( days )和可能的票证选项作为输入,并给出需要购买的票证列表(以输入的票证选项数组的索引形式)。皮特

Petya的值勤时间表以数字数组的形式给出(从1到100,包括1到100),每个数字表示值勤日的序号:

 [2, 5, 10, 45] //     , ,        . 

每个票证由以下界面描述:

 interface Ticket { duration: number; //  ,           ,    ( 1  100 ) cost: number; //   ( 1  100 ) } 

票证选项的数量不超过10,并且可以确保所有票证的价格都不同,并且票证有效期越长,一天的费用就越低。

该解决方案必须作为CommonJS模块提供:

 module.exports = function (days, tickets) { // Your code here. }; 

RE裁决还意味着提交的解决方案不正确。

其他选项
例子

进入结论
 const days = [1, 2, 4, 6, 7, 8, 9, 10, 20]; const tickets = [ { cost: 3, duration: 1 }, { cost: 10, duration: 7 }, { cost: 20, duration: 30 } ]; 
[0, 0, 1]

在第一天和第二天,佩蒂亚需要购买一日票,第四天是七日,第二天又是第二天。

这种票的总费用将是最低的: 19

解决方案


一种可能的解决方案是动态编程方法,即:

1.值班小第一天。
2.为了找到当天最佳的解决方案,我们为每张票计算可能的选项。 每个此类选项均包括机票价格和该机票到期日后值勤当天最佳解决方案的成本。 类似地计算第二项,从而获得递归。
3.此外,如果有几个这样的选项,请考虑票数。
4.在过渡期间应特别注意缓存解决方案。

solution.js
 module.exports = function (days, tickets) { if (days.length === 0 || tickets.length === 0) { return []; } tickets = tickets .map((ticket, idx) => ({ ...ticket, idx })) .sort((a, b) => a.duration - b.duration); const daysSolutions = new Map(); function getDaySolution(idx) { if (daysSolutions.has(idx)) { return daysSolutions.get(idx); } const solution = { totalCost: Number.POSITIVE_INFINITY, totalTickets: Number.POSITIVE_INFINITY, ticketToBuy: null, next: null }; for (let i = 0, j = idx; i < tickets.length && j < days.length; i++) { while (j < days.length && days[j] < days[idx] + tickets[i].duration) { j++; } const nextDaySolution = j < days.length ? getDaySolution(j) : null; let totalCost = tickets[i].cost; let totalTickets = 1; if (nextDaySolution) { totalCost += nextDaySolution.totalCost; totalTickets += nextDaySolution.totalTickets; } if ( totalCost < solution.totalCost || (totalCost === solution.totalCost && totalTickets < solution.totalTickets) ) { solution.totalCost = totalCost; solution.totalTickets = totalTickets; solution.ticketToBuy = tickets[i].idx; solution.next = nextDaySolution; } } daysSolutions.set(idx, solution); return solution; } let solution = getDaySolution(0); const res = []; while (solution) { res.push(solution.ticketToBuy); solution = solution.next; } return res; }; 



这是为后端开发人员解析任务的链接

Source: https://habr.com/ru/post/zh-CN460139/


All Articles