В этом блоге я рассказываю о своем предыдущем сообщении: управление большими обозначениями O и даю ему шанс объяснить технику для улучшения некоторых алгоритмов.
Я буду смотреть специально при устранении вложенных петлей посредством запоминания, чтобы эти примеры перешли от O (n^2) к O (n) Анкет В предстоящем блоге я рассмотрю улучшение некоторых рекурсионных решений.
Записка
Эта техника включает в себя использование Объект В JavaScript или любой другой структуре данных с парами ключей (на других языках), чтобы временно хранить некоторые данные, пока выполняется алгоритм. Используется структура данных пары ключей, потому что клавиши уникальны, поэтому тот же клавиш не будет генерироваться более одного раза. Таким образом, если к определенным данным необходимо получить доступ несколько раз, к ним можно хранить только в одном запуска в форме пар значений ключей, а затем можно получить доступ несколько раз без необходимости его восстановления. Когда этот метод не используется, идентичные данные создаются снова и снова, что делает алгоритм более медленным.
Этот подход также позволяет добавить некоторую логику, которая помогает получить решение одновременно, мы получаем доступ к данным объекта; Как мы увидим в следующем примере.
Две суммы
Код в песочнице
Основным примером использования объекта меморизации (в JavaScript) является две суммы, которая является проблемой LeetCode #1. Две сумма занимает множество целых чисел и целевую сумму и просит найти какие -либо два числа из массива, которые добавляют в цель, но мы возвращаем их индексы. Решение грубой силы:
const twoSumSlow = (numbers, sum) => {// O(n^2) big o complexity
for(let i = 0; i [0,4] which are the indexes of the correct numbers
// because 1 + 9 = 10
В этом решении используется вложенная петля (числа [i] против чисел [j]), чтобы проверить каждую комбинацию чисел в массиве, чтобы увидеть, добавляют ли они к требуемой сумме.
Однако то, что делает это решение медленным, так это то, что каждое число посещается более одного раза вложенным циклом, поэтому, когда размер массива увеличивается, количество посещений родительского и детского петля по каждому числу растет в геометрической прогрессии, что делает решение дорогой.
Взгляните на решение объекта Memoization:
const twoSumFast = (numbers, sum) => {// O(n) big O time complexity
const dataObject = {}
for(let i =0; i< numbers.length; i++){
dataObject[numbers[i]] = i // create memo object
}
for(let i =0; i< numbers.length; i++){
const missingNumber = sum - numbers[i]
if(dataObject[missingNumber] && dataObject[missingNumber] !== i){
return [dataObject[missingNumber], i] // return missing number's index and current index
}
}
}
const numbers = [1,2,7,8,9]
const sum = 10
twoSumFast(numbers, sum)
// returns => [0,4] which are the indexes of the correct numbers
// because 1 + 9 = 10
Мы реализуем память, создав DataObject с массивом чисел в качестве ключей объекта и индексом каждого числа в массиве в качестве соответствующего значения.
dataobject = {
1: 0,
2: 1,
7: 2,
8: 3,
9: 4
}
Таким образом, мы можем добавить второй цикл (который не вложен), который проверяет на получение Пропавшая штучка Это добавляет к нашей желаемой стоимости.
Создание «объекта мемуазации» DataObject Позволяет нам хранить все цифры в виде уникальных клавиш, к которым можно получить как DataObject [hispotNumber] Чтобы получить индекс недостающего числа для «двух сумм».
Добавленная/уникальная логика в этом примере происходит от использования косвенного способа проверки суммы через недостающее число, которое обнаруживается путем вычитания текущего числа из суммы.
const missingNumber = sum - numbers[i]
Затем мы можем добавить эту логику при доступе к клавишу объекта с помощью DataObject [hispotNumber] Анкет И поэтому мы убиваем двух птиц одним магазином, генерируя Пропавшая штучка а также видит, существует ли это в качестве ключа объекта.
if(dataObject[missingNumber] && dataObject[missingNumber] !== i){
return [dataObject[missingNumber], i]
}
В примере вложенного цикла мы устанавливаем логическое равенство суммы в вложенном цикле, что увеличивает сложность времени.
//nested loop w/ i and j
if(numbers[i] + numbers[j] === sum){
return [i, j];
}
Подсчет дубликатов
Следующий пример – адаптация от Аарон Мартин (Ajmanntech) Видео на YouTube. Этот алгоритм берет список чисел и считает дубликаты.
Код в песочнице
const countDuplicatesSlow = (numbers) => { // O(n^2) big o complexity
let result = []
for(let i = 0; iВ этом примере мы используем вложенную петлю, чтобы оценить каждый элемент (внешний цикл) против остальных элементов (внутренних для цикла) и начать подсчитать, сколько дубликатов у нас на массиве.
const duplicateNumbers = [1,2,3,2,1,2] countDuplicatesSlow(duplicateNumbers) // returns => [Found a total of: (2) number 1s, // Found a total of: (3) number 2s, // Found a total of: (1) number 3s]
Итак, сначала мы создаем цикл, чтобы сохранить уникальные элементы в качестве ключей к объекту с пустым массивом в качестве значения, а затем мы делаем второй цикл, чтобы подсчитать дубликаты до соответствующих клавиш.
Код в песочнице
const countDuplicates = (numbers) => { // O(n) big o complexity
let result = {}
for(let i = 0; iОтсутствие вложенной петли позволяет алгоритму быть O (n) вместо O (n^2).
Оригинал: “https://dev.to/santispavajeau/improving-big-o-eliminating-nested-loops-with-a-data-object-2d03”