Interview Cake — одно из лучших моих вложений в изучение алгоритмов и подготовку к техническим собеседованиям. У них есть обширный глоссарий необходимых алгоритмов, за которым следуют интересные вопросы, которые вы можете решить в их текстовом редакторе. Вы даже можете запустить свое решение в их тестах для отладки!

Одна из причин, по которой я потратился на InterviewCake, заключалась в том, что мне нужен был легкий доступ к решениям JavaScript. Cracking the Coding Interview написан на Java, поэтому приятно иметь возможность увидеть и попрактиковаться в языке, который вы будете использовать во время собеседования.

У них есть выбор из 14 языков, включая Python, C#, Go, JavaScript, Objective-C, PHP, Python и Ruby.



Вот вопрос из приведенной выше ссылки, который мы рассмотрим:

Ваша компания создала собственный календарь под названием HiCal. Вы хотите добавить функцию просмотра времени в течение дня, когда доступны все.

Для этого вам нужно знать, когда у какой-либо команды есть собрание. В HiCal собрание хранится в виде объектов ↴ с целочисленными свойствами startTime и endTime. Эти целые числа представляют количество 30-минутных блоков после 9:00.

Например:

{ startTime: 2, endTime: 3 }  // meeting from 10:00 – 10:30 am
{ startTime: 6, endTime: 9 }  // meeting from 12:00 – 1:30 pm

Цель: Написать функцию mergeRanges(), которая принимает массив нескольких диапазонов времени встречи и возвращает массив сжатых диапазонов.

  • *Мы не можем предполагать, что собрания проходят по порядку. Это важный ключ к эффективному решению проблемы.

Пограничные случаи:

[{ startTime: 3, endTime: 5}, { startTime: 4, endTime: 6}]
  1. Встречи должны быть объединены, чтобы вернуть [{ startTime: 3, endTime: 6}]. Время начала первого собрания меньше времени начала второго собрания, а время окончания первого собрания меньше времени начала второго собрания.

2. Что если endTime первого совпадает с startTime второго? например.

[{ startTime: 4, endTime: 6}, { startTime: 6, endTime: 9}]

Затем мы должны рассмотреть, когда endTime первого собрания равно startTime второго собрания.

Собираем вместе:

Есть более простой способ увидеть шаблон для встреч, которые перекрываются. Если endTime первого больше или равно startTime второго, они должны быть объединены. Пока мы рассматриваем собрание с более ранним startTime как первая встреча, это сработает.

Мы могли бы настроить два цикла for для сравнения всех собраний, один с i = 0, а другой j = i + 1, но это дало бы нам время выполнения 0(n2).

В настоящее время наш массив встреч не отсортирован, но что, если бы он был отсортирован по времени начала? Затем мы могли бы просто перебрать наш отсортированный массив и проверить с помощью логики, которую мы уже подробно описали. Сортировка массива — logn, а проверка каждого элемента в отсортированном массиве — 0(n). n log n лучше, чем 0 (n2), так что это будет лучшим подходом.

Давайте работать над решением вместе:

Ознакомьтесь с моей сутью здесь для решения и пошагового руководства. Мои извинения за появление превью изображения.

function mergeRanges(meetings){
//We are calling #sort on meetingsCopy, which is an array of meeting objects. sort() will sort items in an array by default
//in ascending order. We are passing in an optional function that provides an alternative way to sort the array.
//For example, if a.startTime (5) - b.startTime(3), this would produce a positive number.
//If a positive number is returned, b will now come first, and a will be pushed forward.
//This pattern will ensure that the smaller numbers come first.
const sortedMeetings = meetingsCopy.sort((a, b) => {
return a.startTime - b.startTime;
});
// initialize merged meetings with the first meeting from sorted meetings We know the first index is the earlier startTime.
const mergedMeetings = [sortedMeetings[0]];
// Loop over the sorted meetings to find the right ones to merge. Access current meeting in loop with currentMeeting.
//As we loop, the i value will increase until it's one less than the length of the mergedMeetings, ie. the last meeting.
for (let i = 1; i < sortedMeetings.length; i++) {
const currentMeeting    = sortedMeetings[i];
const lastMergedMeeting = mergedMeetings[mergedMeetings.length - 1];
if (currentMeeting.startTime <= lastMergedMeeting.endTime) {
// [{startTime: 3, endTime: 5}, //{startTime: 3, endTime: 4}]
//--> {startTime: 3, endTime: //5}
// To merge them, we also have to make sure we take the larger endTime. Unlike startTimes, endTimes are not sorted.
//Math.max() will return the assigned the higher value to the variable lastMergedMeeting.endTime
lastMergedMeeting.endTime = Math.max(lastMergedMeeting.endTime, currentMeeting.endTime);
} else {
// Add the current meeting since it doesn't overlap
mergedMeetings.push(currentMeeting);
}
}
return mergedMeetings;
}