да. Это. Снова 2:35. Да, моя жена спит, а я снова возвращаюсь к клавиатуре, щелкаю и щелкаю, пока Стиви Уандер играет «Сэр Герцог» на заднем плане, а рядом со мной готовится паровой чай с яблоками и клюквой. Действительно плохо ложиться спать так поздно, но это так весело! И еще веселее решать какие-то странные головоломки с Javascript, пока я занимаюсь этим! Я даже не собираюсь писать здесь отказ от ответственности, утверждая, что я вменяемый человек, но эй, писать сообщения в блоге Javascript в 2 часа ночи - это нормально, правда? ПРАВИЛЬНО?!

Что ж, даже если это не так, Стиви начал играть "Superstitious", а это значит, что я в еще лучшем настроении и подстраиваюсь под песню (это действительно невозможно, я смею вас попробовать). Это также означает, что пора заняться этой головоломкой!

К вашему сведению: я не забывал писать сообщения обо всем остальном, что собирался сделать во время моего сообщения о рекурсии, но это возникло, и я подумал, что это будет весело, поэтому я поместил его здесь. Это также напоминает мне о том, что я должен писать несколько интересных вопросов, которые возникают, когда я на них отвечаю!

Заявление об ограничении ответственности: однажды я найду здесь правильный отступ. Сегодня (сегодня вечером) не ночь / день. Но это случится, я в этом уверен.

Хорошо, вот и большая проблема:

Напишите функцию, которая принимает целое число N и возвращает спиральную матрицу NxN.

…..

Позвольте мне наглядно прояснить ситуацию: наша гипотетическая матричная функция примет число и вернет матрицу с высотой и шириной этого числа, где числа увеличиваются по спирали вокруг и внутрь, например:

Например, вызов функции matrixMaker (4) даст:

[ [1,2,3,4]
[ 12,13,14,5]
[11,16,15,6]
[10,9,8,7] ]

Это выглядит безумно сбивающим с толку, вероятно, в чем я не могу вас винить, так как меня это тоже сильно сбило с толку. Но давайте разберемся с этим:

  1. Количество строк и столбцов будет равно количеству, переданному в качестве аргумента.
  2. Наибольшее число в спирали для каждой силы будет квадратом переданного числа. В приведенном выше примере это 16, потому что 4 ^ 2 = 16. Если бы у нас была матрица из 3, наибольшее число было бы 9, и оно будет выглядеть так: [1,2,3]
    [8,9,4]
    [7,6,5]
  3. Нам нужно написать функцию, которая учитывает количество столбцов и строк и продолжает выполнять итерацию, сжимая спираль.
  4. Вероятно, было бы полезно, если бы мы заранее создали большой массив-оболочку, создали x внутренних массивов, а затем заполнили их.

Имея все это в виду, давайте перейдем к простым частям, а затем перейдем к сложным. Не волнуйтесь, это не так уж и плохо. Если это так, всегда есть возможность аккуратно закрыть свой ноутбук, встать, выйти на улицу, прогуляться, поехать в аэропорт, сесть в самолет и больше никогда не возвращаться. Но если вы решили остаться, давайте ЭТО СДЕЛАТЬ:

Шаг первый: давайте определим функцию, настроим большой внешний массив и заполним его:

function matrix(num) {
let iter = 1, bigArr = [];
 while(iter <= num) {
 bigArr.push([])
 iter++
 } 
 return bigArr
}

Ok. Уф. Это было интенсивно, правда? # Рабочий день, амирит? О, ты хочешь сказать, что мы еще не закончили? Хорошо…

Шаг 2. Давайте подумаем: нам нужны переменные, чтобы отслеживать текущий столбец, с которым мы работаем, текущую строку, максимальное количество столбцов и максимальное количество строк. Это поможет убедиться, что у нас есть все четыре основных фактора, которые нам нужны: текущее положение и максимальное положение осей x и y соответственно. Вот небольшой наглядный пример:

Итак, давайте вызовем те переменные, которые будут отслеживать наши строки и столбцы minCol, maxCol, minRow и maxRow, и добавим их в наши начальные объявления переменных:

function matrix(num) {

let iter = 1, bigArr = [], minCol = 0, maxCol = num-1, minRow = 0, maxRow = num-1;
 while(iter <= num) {
 bigArr.push([])
 iter++
 } 
 return bigArr
}

Ok. Далее: перейдем к сути этой функции: фактическому размещению чисел. Мы знаем, что нам нужно убедиться, что цикл остановлен, и мы можем сделать это, «закрутив винты» как в строках min / max, так и в столбцах min / max. Уменьшая доступные столбцы и строки и увеличивая минимум обоих, в конечном итоге они встречаются, давая нам середину (при условии, что они увеличиваются и уменьшаются с одинаковой скоростью).

Давайте сделаем это шаг за шагом. Мы знаем, что сначала нам нужно пройти через верхнюю часть наших массивов, которая в нашем примере матрицы (4) будет [1,2,3,4].

Давайте посмотрим:

function matrix(num) {
 let maxRow = num-1, maxCol = num-1, minRow = 0, minCol = 0, iter =1 bigArr = [];
 while(iter <= num) {
 bigArr.push([])
 iter++
 } 
 iter = 1;
while((minCol <= maxCol) && (minRow <= maxRow)) {
for(let curCol = minCol; curCol <= maxCol; curCol++) {bigArr[minRow][curCol] = iter++}
 minRow++

 }
 return bigArr
}

Давайте посмотрим на первую строку внутри этого цикла while:

Мы говорим, что хотя текущий столбец (который начинается с 0, что означает крайний левый столбец) меньше максимального столбца (который в конечном итоге становится 4-м индексом массива в нашем примере), мы хотим выполнить цикл, который будет бегать «горизонтально». Это то, что мы хотим в первую очередь. Прокрутите все это и все время вставляйте номер нашего итератора. Мы убеждаемся, что вводим правильное число в нужном месте, говоря, что массив, на который мы нацеливаемся в bigArr, является первым на данном этапе. Индекс этого массива, естественно, является значением, которое мы увеличиваем.

Как только мы закончим, мы увеличиваем minRow. Это делает кое-что очень, очень важное: мы начинаем спускаться, а не вбок. После того, как мы заполнили массив, мы хотим переместиться вниз с правой стороны массивов и заполнить их (см. Диаграмму выше).

// текущие значения: maxCol: 3, maxRow: 3, minCol: 0, minRow: 1

Итак, теперь мы хотим зациклить эту правую сторону. Как мы это делаем? Поместив следующую строку в:

for(let curRow = minRow; curRow <= maxRow; curRow++) {bigArr[curRow][maxCol] = iter++}
maxCol —

Это происходит следующим образом: мы устанавливаем для текущей строки минимальную строку (которую мы увеличили до 1 в строке чуть выше). Мы увеличиваем эту переменную, пока она не достигнет значения maxRow (четвертого индекса). И вот что интересно: мы также увеличиваем номер массива, в который помещаем значения!

Итак, в первый раз, когда мы вводим значение, мы помещаем его во второй массив (помните, мы увеличили минимальное значение массива!), Затем третий, затем четвертый. В какой индекс мы помещаем это значение? Ну, maxCol, это четвертый индекс! Мы только что перешли на правую часть этой матрицы!

Знаю, знаю, это сбивает с толку. Но продумайте шаги: мы проходим верхний массив как обычный цикл. Затем мы говорим: теперь минимальная строка находится на одну строку ниже, потому что верхняя строка заполнена. Затем мы перебираем значение, которое в конечном итоге становится массивом, в который мы помещаем значения (что означает, что мы идем вниз). В каждом из них мы помещаем значение в последний индекс этого массива. Бум.

В конце концов, все важные файлы maxCol -. Это потому, что этот столбец теперь заполнен, поэтому последний столбец, который нам теперь нужно заполнить, на один меньше, чем последний.

Если это поможет, вот диаграмма, в которой мы сейчас работаем:

// текущие значения: maxCol: 2, maxRow: 3, minCol: 0, minRow: 1

Далее нам нужно вернуться назад! Обратное время цикла!

Yaaaay! (Кстати, я знаю, что вам интересно, так что да, я уже дал другому чаю остыть)

for(let curCol = maxCol; curCol >= minCol; curCol — ) {bigArr[maxRow][curCol] = iter++}
maxRow —

Теперь нам нужно снова пойти налево. Поскольку это контролируют столбцы, мы собираемся уменьшить их, начиная с maxCol и двигаясь влево. Помните, что у нас есть maxCol в качестве предпоследнего столбца, что имеет смысл, если вы посмотрите на последнее изображение. Теперь, пока мы не дойдем до minCol, мы уменьшаем значение и идем влево. Последняя строка - это целевой массив, а curCol - это крайнее левое значение. Тогда угадайте, что? Последняя строка заполнена, поэтому maxRow, который мы можем заполнить, должен быть уменьшен.

Диаграмма:

// текущие значения: maxCol: 2, maxRow: 2, minCol: 0, minRow: 1

Ok. Теперь следующее направление, в котором мы должны двигаться, - вверх! Итак, какое значение мы будем уменьшать? Ряд! Мы просто уменьшили столбцы, поэтому нам нужно уменьшить столбцы!

for(let curRow = maxRow; curRow >= minRow; curRow — ) {bigArr[curRow][minCol] = iter++}
minCol++

Мы устанавливаем для текущей строки значение maxrow, которое мы теперь уменьшили, и уменьшаем его, пока не достигнем minrow, который мы увеличили. Видите, как мы приближаемся к середине квадрата?

Уменьшая количество строк, мы добавляем повторяющееся значение в mincol или индекс 0 массива.

// текущие значения: maxCol: 2, maxRow: 3, minCol: 1, minRow: 1

Это одна петля! Весь этот беспорядок находится внутри цикла while, поэтому он будет работать до тех пор, пока любое из условий не станет ложным. Святая моли. Да, и не забудьте вернуть массив в конце:

function matrix(num) {
 let maxRow = num-1,
 maxCol = num-1,
 minRow = 0,
 minCol = 0,
 iter = 1, 
 bigArr = [];
 while(iter <= num) {
 bigArr.push([])
 iter++
 } 
 iter = 1;
 while((minCol <= maxCol) && (minRow <= maxRow)) {
 for(let curCol = minCol; curCol <= maxCol; curCol++) {bigArr[minRow][curCol] = iter++}
 minRow++
 for(let curRow = minRow; curRow <= maxRow; curRow++) {bigArr[curRow][maxCol] = iter++}
 maxCol — 
 for(let curCol = maxCol; curCol >= minCol; curCol — ) {bigArr[maxRow][curCol] = iter++}
 maxRow — 
 for(let curRow = maxRow; curRow >= minRow; curRow — ) {bigArr[curRow][minCol] = iter++}
 minCol++
 }
 return bigArr
}

Уф. Ok. Сейчас для меня это уже слишком. Мне нужно спать, потому что сейчас 4:07. Но я оставляю вас с этими чудесными размышлениями, а также с вопросами о том, почему кто-то заставляет кого-либо делать это или, что еще хуже, быть достаточно сумасшедшим, чтобы писать об этом. Чудак. G‘Night / Morning!