Skip to content

977. Squares of a Sorted Array#51

Open
GrishinAnton wants to merge 4 commits into
masterfrom
977.squares-of-a-sorted-array
Open

977. Squares of a Sorted Array#51
GrishinAnton wants to merge 4 commits into
masterfrom
977.squares-of-a-sorted-array

Conversation

@GrishinAnton
Copy link
Copy Markdown
Owner

Решение через bucket sort. Отсортиовал, а потом просто возвел в степень.

Сложность O(n) и по памяти получается O(n + m + k)
n это входящий массив
m - это хешмапа
k - это возвращаемый массив

@GrishinAnton GrishinAnton requested a review from vitkarpov May 11, 2020 15:50
@vitkarpov
Copy link
Copy Markdown
Collaborator

m - это хешмапа
k - это возвращаемый массив

Что вот это за числа? У тебя есть n – количество элементов в массиве, это понятно.

@vitkarpov
Copy link
Copy Markdown
Collaborator

Решение через bucket sort. Отсортиовал, а потом просто возвел в степень.

Мне кажется странным, что ты всюду пытаешься использовать bucket sort. Помни, что это не бесплатно — массив получается сильно разреженным, тратится память.
Не проще завести обычный мап, там сделать подсчёты как ты хочешь, типа сколько таких элементов по модулю встречалось, и разложить в результат квадраты, пройдясь по отсортированным ключам мапы?

@vitkarpov
Copy link
Copy Markdown
Collaborator

В принципе, решение валидное, но требует O(n) дополнительной памяти (если использовать мапу, а не bucket sort, если же использовать его — то O(m), где m максимальное значение элемента в массиве, наверное, в своей оценке ты это имел в виду. Что, кстати говоря, может быть довольно большим числом, а-ля 10^9 степени и вот ты уже сжираешь мегабайты памяти не понятно зачем).

Давай сделаем без дополнительной памяти, выходной массив для результата за дополнительную память не считаем.

@GrishinAnton
Copy link
Copy Markdown
Owner Author

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

Ну научился пользоваться молотком...теперь все гвозди:) Мне понравилась идея бакетсорта:)

По поводу мапы, получается , это же тоже память? Объект я заветси не могу, так как значения повторяются. new Map - можно, но память, но меньше.
Но если Map заводить это же цикл дополнительный.
Первый положу в меп сразу с квадратом.
Второй отсортировать пем
Третий уже разложить.

Экономлю на памяти, трачу на цикл.

@vitkarpov
Copy link
Copy Markdown
Collaborator

vitkarpov commented May 13, 2020

По поводу мапы, получается , это же тоже память? Объект я заветси не могу, так как значения повторяются.

Не, я имею в виду массива (hashmap = []) обычный объект (hashmap = {}). В чем разница?
Ты кладёшь туда два значения, скажем 1 и 10^9. В случае с объектом это два значения, в случае с массивом это 10^9 значений, потому что между двумя этими значениями создадутся 10^9 - 2 undefined-ов чтобы удовлетворить интерфейсу массива (т.е. доступ по индексу). Это, наверняка, как-то оптимизируется в V8, но зачем так делать не понятно. Кстати, это и называется разреженным массивом, когда у тебя большие промежутки между элементами.
Это тоже память, да, но намного меньше. Порядка количества элементом в массиве, а не порядка самого большого значения элементов (которое реально можно быть большим, вот как в примере выше, из всего 2-х элементов это превратилось в конские 10^9)

@vitkarpov
Copy link
Copy Markdown
Collaborator

Вывод такое: если тебе нужен хэш-мап — используй {} или Map

@vitkarpov
Copy link
Copy Markdown
Collaborator

В любом случае, это решение тоже с дополнительной память. Здесь можно совсем без этого. Обрати внимание, что значения в массиве отсортированы. Это значит есть некоторая точка в этом массива, которая даст первый элемент в массиве квадратов, можешь сказать вообще говоря что это за точка, что за значение?

@GrishinAnton
Copy link
Copy Markdown
Owner Author

В любом случае, это решение тоже с дополнительной память. Здесь можно совсем без этого. Обрати внимание, что значения в массиве отсортированы. Это значит есть некоторая точка в этом массива, которая даст первый элемент в массиве квадратов, можешь сказать вообще говоря что это за точка, что за значение?

По идея я могу взять серидину массива и это сразу будет старт.
Потом я могу брать 1 левый элемент и 1 правый элемент, возводить из в степень и какой меньше будет следующим элементом. Какой больше третьим элементом. И так по 1 в каждую сторону.

@GrishinAnton
Copy link
Copy Markdown
Owner Author

GrishinAnton commented May 13, 2020

По поводу мапы, получается , это же тоже память? Объект я заветси не могу, так как значения повторяются.

Не, я имею в виду массива (hashmap = []) обычный объект (hashmap = {}). В чем разница?
Ты кладёшь туда два значения, скажем 1 и 10^9. В случае с объектом это два значения, в случае с массивом это 10^9 значений, потому что между двумя этими значениями создадутся 10^9 - 2 undefined-ов чтобы удовлетворить интерфейсу массива (т.е. доступ по индексу). Это, наверняка, как-то оптимизируется в V8, но зачем так делать не понятно. Кстати, это и называется разреженным массивом, когда у тебя большие промежутки между элементами.
Это тоже память, да, но намного меньше. Порядка количества элементом в массиве, а не порядка самого большого значения элементов (которое реально можно быть большим, вот как в примере выше, из всего 2-х элементов это превратилось в конские 10^9)

Тут согласен. hash подходит, просто я не сразу сообразил как в нем хранить одинаковые значения?
Например если у нас две тройки? В объекте не может быть два одинаковых ключа.

@vitkarpov
Copy link
Copy Markdown
Collaborator

Например если у нас две тройки? В объекте не может быть два одинаковых ключа.

А в массиве разве может быть? В чем разница?

@vitkarpov
Copy link
Copy Markdown
Collaborator

В любом случае, это решение тоже с дополнительной память. Здесь можно совсем без этого. Обрати внимание, что значения в массиве отсортированы. Это значит есть некоторая точка в этом массива, которая даст первый элемент в массиве квадратов, можешь сказать вообще говоря что это за точка, что за значение?

По идея я могу взять серидину массива и это сразу будет старт.
Потом я могу брать 1 левый элемент и 1 правый элемент, возводить из в степень и какой меньше будет следующим элементом. Какой больше третьим элементом. И так по 1 в каждую сторону.

Да, идея верная. Только не понятно почему «середину». Пример: [-2,-1,0,1,2,3,4,5,6]. Почему я должен взять 2 (середину)?

@GrishinAnton
Copy link
Copy Markdown
Owner Author

Например если у нас две тройки? В объекте не может быть два одинаковых ключа.

А в массиве разве может быть? В чем разница?

Тогда понял. Получается я сначапла собираю числа с их кол-вом ключ число - значение кол-во.
Потом сортирую, а потом возвожу в степень.

@GrishinAnton
Copy link
Copy Markdown
Owner Author

В любом случае, это решение тоже с дополнительной память. Здесь можно совсем без этого. Обрати внимание, что значения в массиве отсортированы. Это значит есть некоторая точка в этом массива, которая даст первый элемент в массиве квадратов, можешь сказать вообще говоря что это за точка, что за значение?

По идея я могу взять серидину массива и это сразу будет старт.
Потом я могу брать 1 левый элемент и 1 правый элемент, возводить из в степень и какой меньше будет следующим элементом. Какой больше третьим элементом. И так по 1 в каждую сторону.

Да, идея верная. Только не понятно почему «середину». Пример: [-2,-1,0,1,2,3,4,5,6]. Почему я должен взять 2 (середину)?

Тогда 0 получается.

@vitkarpov
Copy link
Copy Markdown
Collaborator

Тогда 0 получается.

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

@GrishinAnton
Copy link
Copy Markdown
Owner Author

@vitkarpov
Погряз и запутался в циклах и условиях:)
Все тесты еще не прохожу, решил показать промежуточный этап наверное:)

@vitkarpov
Copy link
Copy Markdown
Collaborator

vitkarpov commented May 14, 2020

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

Я бы как-то так делал (псевдокод, пишу с листа, не запускал):

const indexOfMin = findIndexOfMin(arr);
let left = indexOfMin;
let right = indexOfMin;

while (left >= 0 || right < arr.length) {
  const sqrLeft = arr[left] ** 2;
  const sqrRight = arr[right] ** 2;

  if (sqrLeft < sqrRight) {
    res.push(srqLeft);
    left > 0 && left--;
  } else {
    res.push(srqRight);
    right < arr.length - 1 && right++;
  }
}

Наверняка, здесь что-нибудь упадёт, но я хочу показать идею.

@vitkarpov
Copy link
Copy Markdown
Collaborator

Пока твой код мне сложно понять 😄

@vitkarpov
Copy link
Copy Markdown
Collaborator

Т.е. ещё раз в чем идея алгоритма:

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

Сложность при этом O(n) т.к. каждый элемент массива может быть обработан только один раз

@GrishinAnton
Copy link
Copy Markdown
Owner Author

@vitkarpov
Не идет эта задача с решением когда расходишься из одной точки. Моя идея когда я определяю точку а потом из нее сразу два указателя веду в две стороны провалилась.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants