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