Другие статьи о решении задач 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 год и 🕸️ Изучите веб-разработку с полным стеком .