JS версия структуры данных четвертая (матрица)

JavaScript LeetCode
JS версия структуры данных четвертая (матрица)
Этот блог относится к «Javascript-версии структуры данных и алгоритма» Учителя Инь Гохуэй.

задний план

На самом деле, строго говоря, матрицу нельзя рассматривать как типичную структуру данных.

Причина, по которой матрица помещена в эту серию, заключается в том, что матрица очень часто появляется в интервью и письменных тестах.

Сегодня мы будем использовать js для реализации еще двух классических алгоритмических задач, связанных с матрицами, на LeetCode.

Определение матрицы не должно быть незнакомо студентам, изучавшим курс «Линейная алгебра» в колледже.Если некоторые студенты не понимают, они могут самостоятельно проверить энциклопедию Baidu.

Не много ерунды, давайте сразу к вопросу.

Спиральная матрица

LeetCode Вопрос 54Оригинальный титульный адрес

Сложность вопроса: средняя

Описание темы

Учитывая матрицу m x n элементов (m строк, n столбцов), вернуть все элементы в матрице в порядке спирали по часовой стрелке.

Пример 1:

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]

Пример 2:

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

Понимание темы

Вопрос требует, чтобы мы обходили каждый элемент по часовой стрелке снаружи внутрь и возвращали их по порядку.


Согласно этой картинке, мы должны четко понимать требования вопроса.Порядок возврата элементов, требуемых вопросом, на картинке от 1 до 16.

Анализ мыслей

Мы можем заметить:

Будь то матрица несколько × несколько, нам нужно пройти по внешнему кругу, прежде чем перейти к обходу соседних с ним элементов внутреннего круга.

Как показано на рисунке выше, мы рассматриваем 1-12 как первый круг, а 13-16 как второй круг, и второй круг будет пройден после того, как будет пройден весь первый круг.

Если есть матрица с более высоким порядком (больше кругов), то также будет обход третьего и четвертого круга.

Таким образом, мы можем думать об обходе каждого круга как о шаге, и повторение этого шага даст нужный нам результат.

Я полагаю, что некоторые студенты догадались, что мы должны решить эту задачу рекурсивно.

Далее, давайте посмотрим, как реализован код.

Код

arr => {
    // map函数用来完成当前矩阵最外一圈的遍历
    // @param1{Array}二维数组 arr 表示当前矩阵
    // @param2{Array}一维数组 result 用来保存遍历结果  
    let map = (arr, result) => {
        // 矩阵的高度即行数
        let n = arr.length
        // 遍历矩阵的每一行
        for(let i = 0; i < n; i++){
            // 若第一行 按顺序插入
            if(i === 0){
                result = result.concat(arr[i])
            } else if (i === n-1){
                // 若最后一行 倒序插入
                result = result.concat(arr[i].reverse())
            } else {
                // 若中间行 插入该行最后一个元素 并将该元素从矩阵中删除
                result.push(arr[i].pop())
            }
        }
        // 将已经遍历的第一行和最后一行从矩阵中删除
        arr.pop()
        arr.shift()
        // 遍历插入最左侧一列 此时删除首位两行后矩阵高度已变为n-2
        for(let j = n - 3; j >= 0; j--){
            // 避免arr[j]长度为空时插入undefined
            if(arr[j].length){
                result.push(arr[j].shift())
            }
        }
        // 截止条件 矩阵有元素就继续递归
        if(arr.length){
            // 把已将遍历元素删除的矩阵进行递归
            return map(arr, result)
        }else{
            return result
        }
    }
    // 将初始矩阵传入, 保存结果的数组初始为空
    return map(arr, [])
}

думать

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

Здесь, основываясь на личном опыте, я резюмирую три общих условия выполнения рекурсии:

  • Операция может быть разбита на небольшие шаги, которые обрабатывают один и тот же процесс.
  • Формат входных данных одинаков для каждого шага
  • Неизвестное количество запусков

в этой теме

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

Три условия рекурсии соблюдены.

Если вы столкнетесь с подобными проблемами в будущем, вы можете обратиться к этим трем пунктам, чтобы определить, можно ли использовать рекурсию.

Повернуть изображение

LeetCode Вопрос 48Оригинальный титульный адрес

Уровень сложности: средний

Описание темы

给定一个 n × n 的二维矩阵表示一个图像。 将图像顺时针旋转 90 度。 
проиллюстрировать: Вам нужно повернуть изображение на месте, что означает, что вам нужно напрямую изменить входную 2D-матрицу.
Пожалуйста, не используйте другую матрицу для поворота изображения.

Пример 1:

Данная матрица =
 [
     [1,2,3], 
     [4,5,6], 
     [7,8,9] 
], 
Поверните входную матрицу на месте, чтобы она стала:
[
    [7,4,1], 
    [8,5,2], 
    [9,6,3] 
]

Пример 2:

Данная матрица =
[
    [ 5, 1, 9,11],
    [ 2, 4, 8,10],
    [13, 3, 6, 7],
    [15,14,12,16]
]
Поверните входную матрицу на месте, чтобы она стала:
[
    [15,13, 2, 5],
    [14, 3, 4, 1],
    [12, 6, 8, 9],
    [16, 7,10,11]
]

Понимание темы

Название понятно: поверните матрицу прямо по часовой стрелке, что чем-то похоже на функцию, которую мы обычно используем для поворота изображения на 90 градусов по часовой стрелке.

И причина, по которой эта задача называется «поворот изображения», заключается именно в том, что методом реализации этой задачи является принцип функции поворота изображения.

Анализ мыслей

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

Столбцы добавляются в каждую строку новой матрицы в порядке снизу вверх.

Но сложность этого вопроса в том, что он требует от нас «повернуть изображение на месте», а значит, мы не можем создать новое двумерное число

Сгруппировать (матрицу), а затем добавить в нее данные, мы можем иметь дело только с исходной матрицей, тогда, если мы имеем дело с исходной матрицей, мы можем только поменять местами положения чисел

Другого пути нет.

Как его обменять?

Взяв пример 1 в качестве примера, сначала мы используем ось средней строки, чтобы сделать матрицу осесимметричной.


Затем используем диагональ 753 как ось осесимметричного


На этом этапе мы получаем желаемый результат, а затем реализуем его с помощью кода.

Код

arr => {
    // 获取矩阵阶数
    let n = arr.length
    let temp
    // 垂直翻转 考虑n的奇偶
    for(let i = 0; i < Math.floor(n / 2); i++){
        for(let j = 0; j< n; j++){
            temp = arr[i][j]
            arr[i][j] = arr[n -1 -i][j]
            arr[n -1 -i][j] = temp
        }
    }
    // 沿对角线反转
    for(let p = 0;p < n - 1; p++){
        for(let q = p + 1; q < n; q++){
            temp = arr[p][q]
            arr[p][q] = arr[q][p]
            arr[q][p] = temp
        }
    }
    return arr
}

Суммировать

На LeetCode также есть много тем, связанных с матрицами. Вы можете попробовать его. Если у вас есть какие-либо вопросы о моем методе, вы можете прийти в область комментариев для обсуждения. Больше обменов мнениями приведет к прогрессу. Я надеюсь, что вы станет мастером как можно скорее.