Другие статьи о решении задач HackerRank: часть 1, часть 2.
Как всегда, мы будем использовать JavaScript (ES6) для решения этой задачи.
В этот раз мы решаем Шоколадный день рождения!
Проблема здесь в том, что у Лили есть плитка шоколада (на самом деле ее много). И она хочет подарить Рону несколько штук на день рождения. Но только для того, чтобы количество полосок было равно месяцу рождения Рона, а сумма весов (каждая полоска может быть разной по весу) должна быть равна дню рождения Рона!
И каждый раз день рождения Рона как-то разный. Для маленькой Лили это действительно непростая задача, так что давайте ей поможем!
Сначала давайте посмотрим на данные, которые мы получаем:
n - amount of bars s - array of bars (s[i] - weight of each bar) d - Ron's birthday m - Ron's birthmonth
А вот пример из задачи, который поможет нам понять проблему.
Вход:
5 1 2 1 3 2 3 2
В этом примере мы должны дать Рону 2 стержня с общим весом 3. И мы должны выяснить, сколько вариантов есть у Лили. Также имейте в виду, что Лили хочет раздать шоколад как один кусок, поэтому мы не будем брать первый (1) и последний (2), но мы можем взять первый (1) и второй (2).
Вот картинка, которая может помочь вам понять логику:
Как видите, у Лили всего два пути, поэтому наш ответ - 2!
Пришло время написать код!
Программно есть два возможных способа написать логику.
Сначала выполните итерацию по массиву столбцов только один раз и сохраните все данные в другом массиве после фильтрации этого нового массива и получения ответа.
Во-вторых, это также итерация баров массива, но на каждой итерации делайте еще одну итерацию от текущей позиции по количеству месяцев и проверяйте, равно ли она количеству дней или нет.
В этой статье мы воспользуемся вторым. Начните с большого количества кода.
let answer = 0; // iterate bars for (let k = 0; k < s.length; k += 1) { let sum = 0; // iterate bars month times for (let j = i; j < m + i; j += 1) { // count sum of weights month times sum += s[j]; } // if counted sum is equal to amount of days // then it's +1 to possible ways! if (sum === d) { answer += 1; } } return answer;
Это уродливый декларативный стиль, который занимает слишком много места! Чтобы сделать код лучше, мы можем исключить переменную ответа и использовать метод уменьшения.
// iterate bars return s.reduce((p, , i) => { let sum = 0; // iterate bars month times for (let j = i; j < m + i; j += 1) { // count sum of weights month times sum += s[j]; } // if counted sum is equal to amount of days // then it's +1 to possible ways! if (sum === d) { return p + 1; } return p; }, 0);
Теперь немного лучше! Но все же мы используем цикл for внутри метода reduce и у нас есть еще одна переменная, давайте ее исправим!
function count (from, to, array, val) { if (from < to) { return count(from + 1, to, array, val + array[from]); } return val; } return s.reduce((p, c, i) => { if (count(i, m + i, s, 0) === d) { return p + 1; } return p; }, 0);
На этот раз у нас нет переменных и циклов for! И наш код теперь выглядит в стиле Функционального программирования. Но это еще не конец, мы все еще можем сжать код, чтобы мы могли заменить блоки if тернарными операторами и удалить функцию глобального подсчета и использовать вместо нее IIFE!
return s.reduce((p, c, i) => (((from, to, array, val) => (from < to) ? count(from + 1, to, array, val + array[from]) : val)(i, m + i, s, 0) === d) ? p + 1 : p, 0);
Это одна строка кода без глобальных переменных / функций и без циклов. Тем не менее, мы можем уменьшить его еще больше, но я думаю, что это уже достаточно сложно понять (на самом деле это не очень хорошо!).
✉️ Подпишитесь на рассылку еженедельно Email Blast от CodeBurst 🐦 Подпишитесь на CodeBurst на Twitter , просмотрите 🗺️ Дорожная карта веб-разработчиков на 2018 год и 🕸️ Изучите веб-разработку с полным стеком .