*Как в том анекдоте - есть две новости, хорошая и плохая* Хорошая в том, что решения из видео, как бы так сказать, "условно верные", то есть для случаев, когда нас удовлетворяют те критерии, которые заявлены в самом видео (ну те самые true true false ) их можно считать удовлетворительными. В конце концов, какая кому разница, каким образом написан код - главное чтобы он выполнял свою задачу в рамках поставленных условий. То есть решал свои бизнес задачи. А плохая в том, что как минимум часть решений (я не имел сил ознакомиться со всеми) не отвечает даже минимальным критериям качества, которые можно было бы предъявить материалу, претендующим на *обучать как делать правильно* *Судите сами* Все свои замечания я размещу в отдельных, дочернем к этому,комментариях. *Все озвученные мной утверждения, опираются на соответствующие им официальные спецификации (например ECMA), и претендуют на истину в последней инстанции, чем дают право, в случае ошибки, указать мне на нее, в форме, обнаруживающей мою некомпетентность, в любых эпитетах* Я не преследую цели дискредитации (зацепить, обидеть) кого-либо, потому любые признаки токсичности, следует интерпретировать как интеллектуальную недоразвитость автора - то есть меня.
1:30:11 - 1:31:02 *Deep Equal: В JavaScript есть одна интересная особенность в* *работе с объектами [...] и это означает что они не могут быть так сравнены* Для того, чтобы понять как в JavaScript работает строгое сравнение (===), нужно знать несколько базовых для него (языка) концепций: 1) В JavaScript нет переменных, а есть только идентификаторы, которые содержат в себе ссылку на данные. То есть когда Вы пишите например: _var ident1 = 10;_ _var ident2 = { name: ‘someName’ };_ _var ident3 = ’some string’;_ То _ident1_ , _ident2_ , _ident3_ содержат в себе ссылки на структуры описывающие данные. То есть, вопреки тому, что Вам рассказывают _ident1_ и _ident3_ не содержит сами данные, но так же как и _ident2_ , содержат ссылку на структуру данных. 2) Данные в JS иммутабельные. То есть неизменны. На языке спецификаций данные - это реальные физические байты информации, которые обозначают термином термином Primitive Value_ То есть объявив строку, средствами языка вы не можете ее изменить. Изменения исходной строки (или любых других Primitive Value), приводят к созданию новой. Следствием этого является тот факт, что когда Вы пишите например: _var str1=”my string”;_ _var str2=”my string”;_ то идентификатор str1 и str2 содержит в себе одну и туже ссылку на одни и те же данные. То есть RunTime не создает две структуры данных с одной и той же строкой. То есть RunTime строго следит за тем, чтобы те Primitive Value которые уже описаны, и заявляются снова в нашем коде, получали ту же самую ссылку. 3) Строгое сравнение в JS (===) сравнивает только ссылки из идентификаторов. Никакого сравнения типов и прочей чепухи о которой Вам рассказывают - нет. Потому, что это не нужно учитывая все 3 пункта. Например: _var myNum=3;_ _var myEnotherNum=3;_ _myNum === myEnotherNum;_ // true Потому что оба идентификатора содержат одну и туже ссылку на структуру описывающую Primitive Value: 3. или _var myObj = { name: ‘someName’ };_ _var myObj2 = myObj;_ _var myEnotherObj2 = { name: ‘someName’ };_ _myObj === myObj2;_ // true _myObj === myEnotherObj2;_ // false _myObj['name'] === myEnotherObj2['name'];_ // true
1:31:12 *Специальное значение NaN и забавный факт о нем* Люди, которые обладают достаточной квалификацией для того, чтобы учить других людей знают, что NaN это состояние числа с плавающей точкой, спецификация которого описана стандартом IEEE 754. Стандарт IEEE 754 это стандарт описывающий: структуру, математику, пограничные случаи - словом все что нужно для реализации работы с подобными числами. Этому стандарту следуют практически все современные языки программирования. Согласно этой спецификации, NaN это число которое не равно ни одному другому числу, в том числе и самому себе. Существование подобной конструкции, обусловлено тем, что существуют ситуации, когда результат, в силу обстоятельств, не может быть вычислен, но при этом он должен всегда оставаться числом. Самый простой пример зачем это нужно - работа алгоритмов оптимизации, которые опираются на тип данных с которыми они работают. По этой причине, ни при каких условиях, конструкция NaN === NaN не может быть true и *всегда будет false* По же причине, абсолютно безграмотно писать код в котором сравнение конструкций содержащих NaN может быть эквивалентно друг другу. Это ровно тоже самое, что требовать чтобы 2 x 2 равнялось не только 4 но и любому другому числу.
1:32:32 *Проверить на тип* Унарный оператор typeof, несмотря на то как он звучит, не проверяет тип данных или структур данных. Унарный оператор typeof возвращает строку, в соответствии с определенными критериями, которые совсем не обязательно зависят от типа оперируемых идентификаторов. И может быть абсолютно любым, в том числе и теми какими Вы сами захотите. При использовании строго сравнения в JS нет никакой необходимости в проверке типа данных, по причине описанной выше в Deep Equal.
*О самой задаче по проверки эквивалентности обьектов* Если в Вашей практике возникла ситуация, когда Вам нужно сравнивать эквивалентность двух структур данных, то это первый признак просчетов в архитектуре Вашего кода. То есть в такой ситуации, нужно искать не способы такую эквивалентность установить, но искать проблемы в коде с целью приведения его архитектуры к состоянию, где подобная проверка не требуется. Если вынести это за скобки, и предположить, что операция установления эквивалентности двух структур данных оправдана, то подобная задача должна решаться либо на уровне отслеживания прототипов структур данных как минимум, или на уровне хеширования данных структуры и сравнения уже хешей как максимум. Но не способами заявленными в видео.
1:47:24 *Что вообще делает функция Bind, она привязывает новый контекст к функции* Функция bind не привязывает контекст. this - в JavaScript это не контекст. И не может быть контекстом. В JavaScript не существует ни одного прямого способа управления контекстом исполнения кода. this это обычный идентификатор, который указывает на данные в зависимости от условий выполнения кода. Например для случая, когда функция вызывается как метод объекта: myObj.myMethod() то RunTime по умолчанию установит this на тот обьект myObj. Если та же функция будет вызвана не как метод объекта, например: var func=myObj.myMethod; func(); то this, по умолчанию, будет указывать на глобальную область видимости или на undefined. И это поведение, сам программист может легко менять. По этим причинам - совершенно неправильно и безграмотно в JavaScript называть this контекстом. Что подтверждает и официальная спецификация ECMA. Соответственно, call и apply не привязывают контекст функции. Но позволяют определить значение идентификатора this.
Реально все круть!!! Некоторые задачи первый раз вижу. Поделюсь еще одним примером бинарного поиска с количеством шагов за которые он находит искомый индекс. Пример: function search(array, target) { let step = 1; let start = 0; let end = array.length - 1; let middle = null; while (start target) end = middle - 1; if (result < target) start = middle + 1; step++; } return -1; } console.log(search([1, 3, 6, 13, 17], 13)); // -> 3 console.log(search([1, 3, 6, 13, 17], 12)); // -> -1
['b', 'a', 'a', 'b', 'c', 'c', 'd', 'e'] - для 4-й задачи ломает алгоритм, функция вернет 'a', хотя ожидалось 'b'. Запись maxFreqStr берет последний элемент в итерации, а в этом массиве будет так: 'b', 'b', 'a', 'a', 'a', 'a'. Исправленный вариант: function highestFrequency(array) { const map = {}; let maxFreq = 0; let maxFreqStr = ''; for (let i = 0; i < array.length; i++) { const current = array[i]; if (map[current]) { map[current]++; } else { map[current] = 1; } } for (let key in map) { if (map[key] > maxFreq) { maxFreq = map[key]; maxFreqStr = key; } } return maxFreqStr; }. Спасибо за видео.
Хочу добавить для тех, кто найдет этот недочет и пишет на java. HashMap в java не сохраняет порядок. Поэтому лучше использовать LinkedHashMap, как реализацию Map.
Более оптимальный вариант function flatten(array) { let res = []; for (let i = 0; i < array.length; i++) { const el = array[i]; if (Array.isArray(el)) { res = res.concat(flatten(el)); continue; } res.push(el); } return res; } console.log(flatten([[1], [[2], [3]], [[[4]]]]))
В задаче про LinkedList в коде закралась ошибочка. Тут 1:24:21 между 15 и 16 строчками нужно добавить this.tail.next = node. То есть сперва перезаписать ссылку у хвоста на следующий элемент, только потом указывать новое значение хвоста.
у linked list разве код вообще работает? вы предлагаете перезаписать ссылку next у хвоста, а затем переписать весь хвост целиком тогда данные о ссылке next у хвоста из строки выше тоже перезапишутся
Более оптимальный вариант function search(array, target) { let startIndex = 0; let endIndex = array.length - 1; do { let middle = Math.floor((endIndex - startIndex) / 2) + startIndex; if (target === array[middle]) return middle; if (target > array[middle]) startIndex = middle + 1; if (target < array[middle]) endIndex = middle; if (startIndex===middle) break; } while (true) return -1; }
по первой задаче стандартными методами тоже можно уместиться в одну строчку function isUnique(str) { return str.split("").every((el, index) => str.lastIndexOf(el) === index); };
другой вариант для function flatten. можно и в одну строку написать для куража) function flatten(matrix) { return matrix.reduce((previousValue, currentValue) => ([ ...previousValue, ...(Array.isArray(currentValue) ? flatten(currentValue) : [currentValue]) ], [])) }
Спасибо большое это чудо! Сегодня начала изучать методы массивов, прошла строки, зашла к вам , чтобы найти для себя практику, и начала смотреть, я в восторге !!!
Вариант первой задачки с линейной сложностью Алгоритма O(n), можно через Set или Map примерно также решить. function isUnique(string) { const detect = {}; for (let i = 0; i < string.length; i++) { if (detect[string[i]]) return false; detect[string[i]] = true; } return true }
@@yehorkaliuzhnyi459 1) как отметили, строка итерируемый объект, не нужен split(''), 2) у Set есть size, незачем его к массивв приводить, 3) в видео так и решено в одну строку
По первому же заданию вопросы: 1. Как можно сделать замеры скорости решений на больших объемах данных? Например, сравнить решение в лоб, с перебором элементов массива (строки) (без indexoflast - обычный перебор с индекса элемента) с решением на Set(). Ведь для Set() нужно обработать весь массив, а решение в лоб даст результат уже на второй итерации (в случае первых двух одинаковых символов). Правильное решение это не только лаконичный код :) Кстати, для лаконичности можно функции в виде стрелочных оформлять - ещё небольшой плюсик на собеседовании
Решение с Set работает за O(n), решение с индексами (не важно с indexoflast или с обычным циклом) работает за O(n^2). Решение на Set в подавляющем большинстве случаев работает намного быстрее, за счет того, что в Set поиск идет за константу. Но в некоторых частных случаях может происходить обратное, тут вы правы, нужно исходить из конкретной задачи. В абстрактной же задаче более правильным решением будет использование Set, как с точки зрения качества кода, так и с точки зрения производительности.
Объект Set ищет элемент с временной сложностью O(1), все равно что доставать или удалить элемент по индексу: new Set ().has(7) - Временная сложность O(1)
В задаче на анаграммы можно в целом лаконично возвращать ```return new Set(sortedArray).size === 1```, так как в случае равенства всех строк, размер Set всегда будет равен единице.
Четвёртая задача (highest frequency). Решение с использованием forEach и filter: function highestFrequency(array) { let maxFrequency = []; array.forEach((str, ind) => { maxFrequency[ind] = array.filter(elem => elem == str).length }) return array[maxFrequency.indexOf(Math.max.apply(null, maxFrequency))] }
задачу с определением является ли массив подмножеством другого массива можно легко решить методом из предыдущей задачи: function arraySubset(source, subset) { source.sort((a,b)=>a-b) subset.sort((a,b)=>a-b) return source.join('').includes(subset.join('')) }
3 задачу можно так решить function removeDupes(str) { let res = '' for (let i = 0; i < str.length; i++) { if(!res.includes(str[i])){ res += str[i] } } return res }
Вариант задачи на анаграммы может быть попроще, вместо двух циклов пройтись одним методом every function allAnagrams(array) { const firstAn = array[0].split('').sort().join(''); return array.every(item => item.split('').sort().join('') === firstAn); }
4 задачу решил так, что б без лишних переменных function highestFrequency(array) { const count = {} for (let i = 0; i < array.length; i++) { count[array[i]] ? count[array[i]] += 1 : count[array[i]] = 1 } let max = Math.max(...Object.values(count)); return Object.keys(count).find(k => count[k] === max); }
🔗 Статья лежит тут: t.me/js_by_vladilen/464 🗣 Получить консультацию по курсу: bit.ly/3jdsV2C Telegram: t.me/js_by_vladilen VK: vk.com/vladilen.minin Instagram: instagram.com/vladilen.minin Result School: Telegram: t.me/result_school_it VK: vk.com/result.school Instagram: instagram.com/result.school.it Наши курсы: Бесплатный курс по HTML & CSS: bit.ly/3vXz7Dx Курс профессия Frontend разработчик: bit.ly/3igSH5t Для тех, кто хочет начать свою карьеру в IT: bit.ly/3wFoPYZ Если не запускается одна из ссылок, попробуйте через другой браузер. JavaScript cообщества: Discord: discord.gg/ZrfQXPVvMa Telegram: t.me/js_by_vladilen_chat Roadmap по каналу: vladilen.notion.site/Roadmap-TH-cam-0b917095c1ec424e9574c2ede36efab9
На ноушне надо стрелочки, разворачивающие решение и доп материал завернуть в лейбл или что-т придумать, а то кликаешь на текст и не разворачивается. Раздражает жуть.
Второе задание можно решить так: function flatten(array) { return array.map(arr => String(arr)).join(',').split(','); } Каждый элемент исходного массива приводим к строке (у массива метод toString по умолчанию работает следующим образом: [1,2] -> '1,2' и [1,2,] -> '1,2'). Если какой-то элемент массива также является массивом, то toString вызывается и у этого элемента, то есть: [1, [2]] => '1,2' Я так понимаю, это происходит рекурсивно, поэтому работает с любой глубиной вложенности. Затем джоиним получившиеся элементы по запятой, разделяем также по запятой и получаем результат
7 задание про анаграммы возможно сделать вообще за O(n)! если сделать допущение что мы используем ограниченное кодировкой количество символов, допустим это ASCII, создаем вектор (массив) из 256 элементов где будут храниться счетчики символов, проходим по 0-вой в массиве строк строчке и инкрементируем по символам, по следующей строчке 1 декрементируем и потом заново инкрементируем по 0-вой строчке, потом декрементируем по 2-рой и т.д (в цикле) пока строчки не закончатся, и далее если мы находим в массиве прогоном число отличное от 0 то выходим с false.
Более оптимальный вариант function deepEqual(a, b) { if (typeof a === "object" && typeof b === "object") { let keysA = Object.keys(a); let keysB = Object.keys(b); if (keysA.length !== keysB.length) { return false; } for (let key of keysA) { if (!deepEqual(a[key], b[key])) { return false; } } return true; } return JSON.stringify(a) === JSON.stringify(b); }
4-я задача у меня даже проще получилась, правда, я метод sort применил. function frequency(arr) { const items = new Map() for (let item of arr) { items.has(item) ? items.set(item, items.get(item) + 1) : items.set(item, 1) } const maxFreq = Array.from(items.entries()).sort((a, b) => b[1] - a[1])[0][0] return maxFreq }
В комментах уже правильно отметили, что в задаче про O(1) в методе "addToTail" после "else" не хватает переопределения "tail.next" на "node", а в методе " removeFromHead" проверки на пустую очередь после удаления и очистку хвоста: if (!this.#length) { this.tail = null; } В статье поправить бы )
Более оптимальный вариант function arraySubset(source, subset) { let map = new Map(); for (let el of subset) { const index = source.indexOf(el, map.get(el) || 0); if (index >= 0) { map.set(el, index + 1) } else { return false; } } return true; }
Вот такое решение первой задачи, мне кажется более элегантным) function isUnique(string){ let arrInput = Array.from(string) let checked = [...new Set(arrInput)] if(arrInput.length == checked.length) { console.log(true); } else { console.log(false); } }
@@VladilenMinin function flatten(array) { let result = []; for (let i = 0, len = array.length; i < len; i += 1) { (Array.isArray(array[i])) ? result.push(...flatten(array[i])) : result.push(array[i]); } return result; }
5 задание можно решить так: const isStringRotated = (str1, str2) => { return str1.split("").sort().join("") === str2.split("").sort().join("") ; } Одну и туже строку ( по символам) метод sort отсортирует абсолютно одинаково, поэтому можем конвертировать строку в массив отсортировать методом sort и сравнить.
Смотря как понять условие задачи. Является ли ротацией рандомная перестановка символов или только упорядоченная? Пример упорядоченной ротации: "abcdef" и "cdefab". Пример рандомной перестановки символов: "abcdef" и "cdbafe".
В 7 задаче можно сделать set первого элемента, а потом в цикле делать set.add каждого элемента и сравнивать длину с первоначальным, если больше стала, то буквы лишние
Здравствуйте, подача материала очень хорошая. С удовольствием смотрю и учусь. В задаче про очередь O(1) вариант со связными списками не используется значение next в создаваемой node. Видимо просто пропущено, но из за этого решение не корректно отрабатывает.
Спасибо!, Вопрос по LinkedList - next ведь не указывает на следующий элемент, он всегда null? в метод addToTail нужно добавить - this.#tail.next = node; а в removeFromHead - this.#head = this.#head.next;
Крутой видос, очень интересно было. Спасибо. Но есть одно маленькое предложение, было бы круто, если бы ты хоть вскользь упоминал где такие решения могут пригодиться. В смысле где может пригодиться узнавать развернута ли строка или сколько раз в строке встречается символ. Очень трудно вообразить такой сценарий.
еще одно решение задачки "Является ли массив подмножеством другого массива": function arraySubset(source, subset) { if (subset.length > source.length) { return false } return source.sort().join('').includes(subset.sort().join('')) }
По поводу 2 задачи с рекурсией я бы по проще это решил ( с учетом того что мы не смотрим на поддержку старых браузеров): function flatten(arr) { let res = arr.flat(); if (res.some(a => Array.isArray(a))) { return flatten(res); } else { return res; } }
Универсальное решение задачи на сумму (любое кол-во скобок и аргументов в них): function add(...args) { const parseArgs = (arr) => { return arr.reduce((acc, arg) => { if (Array.isArray(arg)) arg = parseArgs(arg) if (!isNaN(+arg)) acc += +arg return acc }, 0) } let current = parseArgs(args) const f = (...xArgs) => { const tmpSum = parseArgs(xArgs) current += tmpSum return f } f.toNum = () => current return f } console.log(add(1, 1, 1)(2)()(3, '2', 'ghf')('4')([2, 0])(-0)(NaN).toNum()) // 16 Владилен и Мурыч - спасибо вам за хорошую задачку! :)))
В 6 задаче наверно следовало бы упомянуть что удалять элементы из массива с помощью оператора delete на практике не рекомендуется, т.к. после такого удаления длина массива не меняется, что может привести к путанице в дальнейшей разработке. В подобном случае наверно стоит использовать метод slice.
const {log} = console; От чела который на codewars 250 место занимает. (Подсмотрел) А по времени, как узнать сколько код выполняется как на 1:45:00 Над кодом log(time) под кодом log(end)
16:10 - Как мы можем пробегаться по вызову функции flat, как по массиву? Я имею ввиду что в константе flat у нас лежит вызов функции flatten(array[i]). Выглядит это след. образом: const flat = flatten(array[i]). И мы пробегаемся циклом for(let j = 0; j
function isUnique(string) { const arr = [] let result = true Array.from(string).forEach(item => arr.includes(item) ? result = false : arr.push(item)) return result }
вот такой огород нагородил )) работает хреновина ) function isUnique(string) { let result = true const arr = string.split('') for(let i = 0; i < arr.length; i += 1){ let count = 0 arr.forEach(item => { if(item === arr[i]){ count += 1 if(count > 1){ result = false } } }) } return result }
Мне кажется в задачке про подсчет повторяющихся строк в массиве не до конца выполняется условие задания. В вашем коде, если я все правильно понял, из массива {a, b, b, a} программа вернет - b. А исходя из условия должна быть возвращена первая встречающаяся - это "а". В последнем ифе на 3 итерации вышепредложенного массива в maxFreqStr будет записана b и в 4ой итерации с кодом в ифе мы получим 2 > 2 и программа вернет b.
К сожалению, в решении многих задач используют неоптимальные с точки зрения сложности и памяти алгоритмы. А так же используются структуры данных, которые заменяют требуемые алгоритмы. А именно их просят продемонстрировать на собеседованиях и такие ответы не принимают. Говорю по опыту прохождения интервью в крупных компаниях. Но в общем и целом - спасибо за материал.
6 алгоритм на плюсах не очень идеален, там пришлось бы наверное итераторы хранить в unordered_map и через if его инициализировать если через std::find найдем элемент и потом при повторе уже в ветке else будем брать уже итератор из map в find-е, как-то так на плюсах; либо без итераторов и find (дабы исключить работу с библиотекой стандартных алгоритмов) пришлось бы хранить по ключу индекса элемент который будем игнорировать, или... можно не удалять элемент(чтобы если это vector не перестраивать всю последовательность) заменять его на элемент какой-то🤔либо заново создавать vector :)) сорри, готовлюсь не к тому языку по алгоритмам))
2-задание. Просто, так мало вложенности получается) function flatten(array, arr) { for (const elem of array) { if (Array.isArray(elem)) flatten(elem, arr) else arr.push(elem) } return arr }
Спасибо за видео! Кто мне скажет, по чему задачи на javascript в основном решают готовыми методами? Мне кажется, что когда решают в ручную, то лучше понимаешь, что и как.
Я могу ошибаться, но в задаче №11 про связанный список (LinkedList) косяк. При добавлении элементов не ставится ссылка на следующий элемент, т.е. next = null всегда. В итоге, если добавить 3 элемента, а затем удалить 2 элемента, то при удалении второго элемента получим ошибку, т.к. при удалении первого элемента мы переключились на null Решение 12 задачи (глубокое сравнение) - какой-то трэш, если без мата. Вот решение в 1 строку: function deepEqual (a, b) { return JSON.stringify(a) === JSON.stringify(b) } Задача 13. Судя по ссылке на определение последовательности: первые два числа равны 0 и 1, а каждое последующее число равно сумме двух предыдущих чисел. Поэтому ПЕРВОЕ число должно быть равно 0, а не 1 (в видео первое число равно 1). Т.е.: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, …
*Как в том анекдоте - есть две новости, хорошая и плохая*
Хорошая в том, что решения из видео, как бы так сказать, "условно верные", то есть
для случаев, когда нас удовлетворяют те критерии, которые заявлены в самом видео
(ну те самые true true false ) их можно считать удовлетворительными.
В конце концов, какая кому разница, каким образом написан код - главное чтобы он
выполнял свою задачу в рамках поставленных условий. То есть решал свои бизнес
задачи.
А плохая в том, что как минимум часть решений (я не имел сил ознакомиться со
всеми) не отвечает даже минимальным критериям качества, которые можно было бы
предъявить материалу, претендующим на *обучать как делать правильно*
*Судите сами*
Все свои замечания я размещу в отдельных, дочернем к
этому,комментариях.
*Все озвученные мной утверждения, опираются на соответствующие им официальные
спецификации (например ECMA), и претендуют на истину в последней инстанции, чем
дают право, в случае ошибки, указать мне на нее, в форме, обнаруживающей мою
некомпетентность, в любых эпитетах*
Я не преследую цели дискредитации (зацепить, обидеть) кого-либо, потому любые
признаки токсичности, следует интерпретировать как интеллектуальную
недоразвитость автора - то есть меня.
1:30:11 - 1:31:02 *Deep Equal: В JavaScript есть одна интересная особенность в*
*работе с объектами [...] и это означает что они не могут быть так сравнены*
Для того, чтобы понять как в JavaScript работает строгое сравнение (===), нужно
знать несколько базовых для него (языка) концепций:
1) В JavaScript нет переменных, а есть только идентификаторы, которые содержат в
себе ссылку на данные. То есть когда Вы пишите например:
_var ident1 = 10;_
_var ident2 = { name: ‘someName’ };_
_var ident3 = ’some string’;_
То _ident1_ , _ident2_ , _ident3_ содержат в себе ссылки на структуры описывающие
данные. То есть, вопреки тому, что Вам рассказывают _ident1_ и _ident3_ не содержит
сами данные, но так же как и _ident2_ , содержат ссылку на структуру данных.
2) Данные в JS иммутабельные. То есть неизменны. На языке спецификаций данные -
это реальные физические байты информации, которые обозначают термином термином
Primitive Value_
То есть объявив строку, средствами языка вы не можете ее изменить. Изменения
исходной строки (или любых других Primitive Value), приводят к созданию новой.
Следствием этого является тот факт, что когда Вы пишите например:
_var str1=”my string”;_
_var str2=”my string”;_
то идентификатор str1 и str2 содержит в себе одну и туже ссылку на одни и те же
данные. То есть RunTime не создает две структуры данных с одной и той же
строкой. То есть RunTime строго следит за тем, чтобы те Primitive Value которые
уже описаны, и заявляются снова в нашем коде, получали ту же самую ссылку.
3) Строгое сравнение в JS (===) сравнивает только ссылки из идентификаторов.
Никакого сравнения типов и прочей чепухи о которой Вам рассказывают - нет.
Потому, что это не нужно учитывая все 3 пункта.
Например:
_var myNum=3;_
_var myEnotherNum=3;_
_myNum === myEnotherNum;_
// true Потому что оба идентификатора содержат одну и туже ссылку на структуру описывающую Primitive Value: 3.
или
_var myObj = { name: ‘someName’ };_
_var myObj2 = myObj;_
_var myEnotherObj2 = { name: ‘someName’ };_
_myObj === myObj2;_ // true
_myObj === myEnotherObj2;_ // false
_myObj['name'] === myEnotherObj2['name'];_ // true
1:31:12 *Специальное значение NaN и забавный факт о нем*
Люди, которые обладают достаточной квалификацией для того, чтобы учить других
людей знают, что NaN это состояние числа с плавающей точкой, спецификация
которого описана стандартом IEEE 754.
Стандарт IEEE 754 это стандарт описывающий: структуру, математику, пограничные
случаи - словом все что нужно для реализации работы с подобными числами. Этому
стандарту следуют практически все современные языки программирования.
Согласно этой спецификации, NaN это число которое не равно ни одному другому
числу, в том числе и самому себе.
Существование подобной конструкции, обусловлено тем, что существуют ситуации,
когда результат, в силу обстоятельств, не может быть вычислен, но при этом он
должен всегда оставаться числом. Самый простой пример зачем это нужно - работа
алгоритмов оптимизации, которые опираются на тип данных с которыми они работают.
По этой причине, ни при каких условиях, конструкция NaN === NaN не может быть true
и *всегда будет false*
По же причине, абсолютно безграмотно писать код в котором сравнение конструкций
содержащих NaN может быть эквивалентно друг другу. Это ровно тоже самое, что
требовать чтобы 2 x 2 равнялось не только 4 но и любому другому числу.
1:32:32 *Проверить на тип*
Унарный оператор typeof, несмотря на то как он звучит, не проверяет тип данных
или структур данных. Унарный оператор typeof возвращает строку, в соответствии с
определенными критериями, которые совсем не обязательно зависят от типа
оперируемых идентификаторов. И может быть абсолютно любым, в том числе и теми
какими Вы сами захотите.
При использовании строго сравнения в JS нет никакой необходимости в проверке
типа данных, по причине описанной выше в Deep Equal.
*О самой задаче по проверки эквивалентности обьектов*
Если в Вашей практике возникла ситуация, когда Вам нужно сравнивать
эквивалентность двух структур данных, то это первый признак просчетов в
архитектуре Вашего кода. То есть в такой ситуации, нужно искать не способы такую
эквивалентность установить, но искать проблемы в коде с целью приведения его
архитектуры к состоянию, где подобная проверка не требуется.
Если вынести это за скобки, и предположить, что операция установления
эквивалентности двух структур данных оправдана, то подобная задача должна
решаться либо на уровне отслеживания прототипов структур данных как минимум, или
на уровне хеширования данных структуры и сравнения уже хешей как максимум. Но не
способами заявленными в видео.
1:47:24 *Что вообще делает функция Bind, она привязывает новый контекст к функции*
Функция bind не привязывает контекст. this - в JavaScript это не контекст. И не
может быть контекстом. В JavaScript не существует ни одного прямого способа
управления контекстом исполнения кода.
this это обычный идентификатор, который указывает на данные в зависимости от
условий выполнения кода.
Например для случая, когда функция вызывается как метод объекта:
myObj.myMethod()
то RunTime по умолчанию установит this на тот обьект myObj.
Если та же функция будет вызвана не как метод объекта, например:
var func=myObj.myMethod;
func();
то this, по умолчанию, будет указывать на
глобальную область видимости или на undefined.
И это поведение, сам программист может легко менять.
По этим причинам - совершенно неправильно и безграмотно в JavaScript называть
this контекстом. Что подтверждает и официальная спецификация ECMA.
Соответственно, call и apply не привязывают контекст функции.
Но позволяют определить значение идентификатора this.
Приятно смотреть видео, когда уже научился по другим видео Владилена, прошёл собеседование с лайв-кодингом и нашёл хорошую работу) Чего и всем желаю!
Тоже, но я бы не сказал прям так смотрел Владилена, но по базам его видеоуроки по js выручил.
когда учится начал и через сколько взяли на работу?
@@___________S_t_a_s___________ привет, начал два года назад. На поиск работы ушёл месяц
@@___________S_t_a_s___________ если усердно прогать будешь, то можно и за пол года на джуна пройти)
@@drunken_rubbish видел тут вакансию пол года уже висит на хантере, джун с реактом вью 3 года опыта, нод, ссс хтп и др джкью за 30 000р.)
использовать во второй задаче и цикл и рекурсию это уже перегрузка идет. вот одно из решений одним циклом:
function flatten(array) {
let i = 0
while(i
чтобы ни было, а Владилен наверное лучший в ютубе русскоязычный объясняльщик теории.
Реально все круть!!! Некоторые задачи первый раз вижу. Поделюсь еще одним примером бинарного поиска с количеством шагов за которые он находит искомый индекс. Пример:
function search(array, target) {
let step = 1;
let start = 0;
let end = array.length - 1;
let middle = null;
while (start target) end = middle - 1;
if (result < target) start = middle + 1;
step++;
}
return -1;
}
console.log(search([1, 3, 6, 13, 17], 13)); // -> 3
console.log(search([1, 3, 6, 13, 17], 12)); // -> -1
const sortik = (array, target, flag, srr=0 ) => {
const sr = Math.floor(array.length / 2)
if (array.length === 1) return array[0] === target ? srr : -1
const res = array[sr] > target ? sortik(array.slice(0, sr), target, 0, srr) :
sortik(array.slice(sr, array.length), target, 1, sr+srr)
return res
}
Владилен, ты просто мега классный чел! Спасибо тебе огромеднейшее! От души!
['b', 'a', 'a', 'b', 'c', 'c', 'd', 'e'] - для 4-й задачи ломает алгоритм, функция вернет 'a', хотя ожидалось 'b'. Запись maxFreqStr берет последний элемент в итерации, а в этом массиве будет так:
'b', 'b', 'a', 'a', 'a', 'a'. Исправленный вариант:
function highestFrequency(array) {
const map = {};
let maxFreq = 0;
let maxFreqStr = '';
for (let i = 0; i < array.length; i++) {
const current = array[i];
if (map[current]) {
map[current]++;
} else {
map[current] = 1;
}
}
for (let key in map) {
if (map[key] > maxFreq) {
maxFreq = map[key];
maxFreqStr = key;
}
}
return maxFreqStr;
}.
Спасибо за видео.
Хочу добавить для тех, кто найдет этот недочет и пишет на java. HashMap в java не сохраняет порядок. Поэтому лучше использовать LinkedHashMap, как реализацию Map.
const maxFreq = Math.max(...Object.values(map));
return array.find(s => map[s] === maxFreq);
1. const uniqueStr = (str) => new Set(str).size === str.length;
Более оптимальный вариант
function flatten(array) {
let res = [];
for (let i = 0; i < array.length; i++) {
const el = array[i];
if (Array.isArray(el)) {
res = res.concat(flatten(el));
continue;
}
res.push(el);
}
return res;
}
console.log(flatten([[1], [[2], [3]], [[[4]]]]))
В задаче про LinkedList в коде закралась ошибочка. Тут 1:24:21 между 15 и 16 строчками нужно добавить this.tail.next = node. То есть сперва перезаписать ссылку у хвоста на следующий элемент, только потом указывать новое значение хвоста.
То-то я смотрю криво работает реализация. Спасибо!
у linked list разве код вообще работает?
вы предлагаете перезаписать ссылку next у хвоста, а затем переписать весь хвост целиком
тогда данные о ссылке next у хвоста из строки выше тоже перезапишутся
Более оптимальный вариант
function search(array, target) {
let startIndex = 0;
let endIndex = array.length - 1;
do {
let middle = Math.floor((endIndex - startIndex) / 2) + startIndex;
if (target === array[middle]) return middle;
if (target > array[middle]) startIndex = middle + 1;
if (target < array[middle]) endIndex = middle;
if (startIndex===middle) break;
} while (true)
return -1;
}
Третье объяснение первой задачи топ! Поняла наконец как работает Set
@VladilenMinin, спасибо видос:) В задаче про сбалансированные скобки используется стэк, а не очередь))
по первой задаче стандартными методами тоже можно уместиться в одну строчку
function isUnique(str) {
return str.split("").every((el, index) => str.lastIndexOf(el) === index);
};
Более затратное выполнение чем при использовании set так что не best practice
Владилен , ты большой молодец , ты очень помогаешь людям!
Ф
другой вариант для function flatten.
можно и в одну строку написать для куража)
function flatten(matrix) {
return matrix.reduce((previousValue, currentValue) => ([
...previousValue,
...(Array.isArray(currentValue) ? flatten(currentValue) : [currentValue])
], []))
}
20:25 Можно использовать Spread оператор: [...new Set('abc')] -> ['a', 'b', 'c']
Спасибо большое это чудо! Сегодня начала изучать методы массивов, прошла строки, зашла к вам , чтобы найти для себя практику, и начала смотреть, я в восторге !!!
Большое спасибо за двойной формат - статья + видео.
Первые 3 задачи решил сам, было очевидно ) Хорошо учит Владилен! Продолжаю.
Вариант первой задачки с линейной сложностью Алгоритма O(n), можно через Set или Map примерно также решить.
function isUnique(string) {
const detect = {};
for (let i = 0; i < string.length; i++) {
if (detect[string[i]]) return false;
detect[string[i]] = true;
}
return true
}
Вот ещё проще
const isUnique = (str) => {
return str.length === […new Set(str.split(“”))].length;
}
@@yehorkaliuzhnyi459 split() не нужен, строка - итерируемый объект
@@yehorkaliuzhnyi459 1) как отметили, строка итерируемый объект, не нужен split(''), 2) у Set есть size, незачем его к массивв приводить, 3) в видео так и решено в одну строку
По первому же заданию вопросы:
1. Как можно сделать замеры скорости решений на больших объемах данных?
Например, сравнить решение в лоб, с перебором элементов массива (строки) (без indexoflast - обычный перебор с индекса элемента) с решением на Set(). Ведь для Set() нужно обработать весь массив, а решение в лоб даст результат уже на второй итерации (в случае первых двух одинаковых символов).
Правильное решение это не только лаконичный код :)
Кстати, для лаконичности можно функции в виде стрелочных оформлять - ещё небольшой плюсик на собеседовании
Решение с Set работает за O(n), решение с индексами (не важно с indexoflast или с обычным циклом) работает за O(n^2). Решение на Set в подавляющем большинстве случаев работает намного быстрее, за счет того, что в Set поиск идет за константу. Но в некоторых частных случаях может происходить обратное, тут вы правы, нужно исходить из конкретной задачи. В абстрактной же задаче более правильным решением будет использование Set, как с точки зрения качества кода, так и с точки зрения производительности.
Объект Set ищет элемент с временной сложностью O(1), все равно что доставать или удалить элемент по индексу: new Set ().has(7) - Временная сложность O(1)
В задаче на анаграммы можно в целом лаконично возвращать ```return new Set(sortedArray).size === 1```, так как в случае равенства всех строк, размер Set всегда будет равен единице.
Четвёртая задача (highest frequency). Решение с использованием forEach и filter:
function highestFrequency(array) {
let maxFrequency = [];
array.forEach((str, ind) => {
maxFrequency[ind] = array.filter(elem => elem == str).length
})
return array[maxFrequency.indexOf(Math.max.apply(null, maxFrequency))]
}
2 задачу можно решить через метод flat
function flatten(array){
return array.flat(Infinity);
}
Да, но IE не одобрит
Задача "Плоский массив" может быть проще)
const flatten = array => {
const arrHasArr = array.some(el => Array.isArray(el));
const flattenArr = arrHasArr ? array.flat() : array;
return arrHasArr ? flatten(flattenArr) : flattenArr;
}
Или ещё проще и безопаснее (без риска переполнения стека вызовов):
const flatten = array => array.flat(Infinity);
Ну это же нужно так вовремя для меня записать это видео. Спасибо, Владилен :)
задачу с определением является ли массив подмножеством другого массива можно легко решить методом из предыдущей задачи:
function arraySubset(source, subset) {
source.sort((a,b)=>a-b)
subset.sort((a,b)=>a-b)
return source.join('').includes(subset.join(''))
}
function deepEqual(param1, param2) {
if (arguments.length === 0) {
return true;
}
return JSON.stringify(param1) === JSON.stringify(param2);
}
3 задачу можно так решить
function removeDupes(str) {
let res = ''
for (let i = 0; i < str.length; i++) {
if(!res.includes(str[i])){
res += str[i]
}
}
return res
}
Более оптимальный вариант
function highestFrequency(array) {
let map = new Map();
let freq = { maxFreqStr: array[0], maxFreq: 1 };
for (let i = 0; i < array.length; i++) {
const el = array[i];
if (map.has(el)) {
const count = map.get(el);
map.set(el, count + 1);
freq = count >= freq.maxFreq ? { maxFreqStr: el, maxFreq: count + 1 } : freq;
continue;
}
map.set(el, 1)
}
return freq.maxFreqStr;
}
Вариант задачи на анаграммы может быть попроще, вместо двух циклов пройтись одним методом every
function allAnagrams(array) {
const firstAn = array[0].split('').sort().join('');
return array.every(item => item.split('').sort().join('') === firstAn);
}
4 задачу решил так, что б без лишних переменных
function highestFrequency(array) {
const count = {}
for (let i = 0; i < array.length; i++) {
count[array[i]] ? count[array[i]] += 1 : count[array[i]] = 1
}
let max = Math.max(...Object.values(count));
return Object.keys(count).find(k => count[k] === max);
}
Первую задачу можно без циклов решить гораздо проще, в одну строчку.
function isUnique(string) {
return new Set(string).size === string.length
}
🔗 Статья лежит тут: t.me/js_by_vladilen/464
🗣 Получить консультацию по курсу: bit.ly/3jdsV2C
Telegram: t.me/js_by_vladilen
VK: vk.com/vladilen.minin
Instagram: instagram.com/vladilen.minin
Result School:
Telegram: t.me/result_school_it
VK: vk.com/result.school
Instagram: instagram.com/result.school.it
Наши курсы:
Бесплатный курс по HTML & CSS: bit.ly/3vXz7Dx
Курс профессия Frontend разработчик: bit.ly/3igSH5t
Для тех, кто хочет начать свою карьеру в IT:
bit.ly/3wFoPYZ
Если не запускается одна из ссылок, попробуйте через другой браузер.
JavaScript cообщества:
Discord: discord.gg/ZrfQXPVvMa
Telegram: t.me/js_by_vladilen_chat
Roadmap по каналу:
vladilen.notion.site/Roadmap-TH-cam-0b917095c1ec424e9574c2ede36efab9
спасибо
На ноушне надо стрелочки, разворачивающие решение и доп материал завернуть в лейбл или что-т придумать, а то кликаешь на текст и не разворачивается. Раздражает жуть.
Владилен спасибо тебе огромное )) До просмотра видео многие задачи мог решить только самым простым и не всегда эффективным способом.
Ура, я уж думал не выйдет. Заранее лайк ! Спасибо.
задача с развертыванием:
function flatten(array) {
return array.flat(Infinity)
}
Обычно в условиях таких задач речь идёт об альтернативных путях решения, автор просто это не упомянул.
Благодарю, Владилен. Было полезно посмотреть видео
Крууууто! Спасибо тебе большое Владилен, ты красава!
Второе задание можно решить так:
function flatten(array) {
return array.map(arr => String(arr)).join(',').split(',');
}
Каждый элемент исходного массива приводим к строке (у массива метод toString по умолчанию работает следующим образом: [1,2] -> '1,2' и [1,2,] -> '1,2').
Если какой-то элемент массива также является массивом, то toString вызывается и у этого элемента, то есть:
[1, [2]] => '1,2'
Я так понимаю, это происходит рекурсивно, поэтому работает с любой глубиной вложенности.
Затем джоиним получившиеся элементы по запятой, разделяем также по запятой и получаем результат
Осознал, что можно сразу привести к строке входящий массив, а затем разделить полученную строку))
const flatten = (array) => String(array).split(',');
@@grbak вот только каждое число в массиве теперь string, а на входе number
@@grbak function flatten(array) {
return String(array).split(',').map((el) => {
return Number(el)
})
}
7 задание про анаграммы возможно сделать вообще за O(n)! если сделать допущение что мы используем ограниченное кодировкой количество символов, допустим это ASCII, создаем вектор (массив) из 256 элементов где будут храниться счетчики символов, проходим по 0-вой в массиве строк строчке и инкрементируем по символам, по следующей строчке 1 декрементируем и потом заново инкрементируем по 0-вой строчке, потом декрементируем по 2-рой и т.д (в цикле) пока строчки не закончатся, и далее если мы находим в массиве прогоном число отличное от 0 то выходим с false.
Огонище!!! Восхитительно!!!
вторая задача
return String(array).split(',').map(item => Number(item))
Более оптимальный вариант
function deepEqual(a, b) {
if (typeof a === "object" && typeof b === "object") {
let keysA = Object.keys(a);
let keysB = Object.keys(b);
if (keysA.length !== keysB.length) {
return false;
}
for (let key of keysA) {
if (!deepEqual(a[key], b[key])) {
return false;
}
}
return true;
}
return JSON.stringify(a) === JSON.stringify(b);
}
Спасибо за труд! Очень полезные задачки)
выпускайте такие видео чаще! и чем сложнее задачи тем лучше!))
4-я задача у меня даже проще получилась, правда, я метод sort применил.
function frequency(arr) {
const items = new Map()
for (let item of arr) {
items.has(item) ? items.set(item, items.get(item) + 1) : items.set(item, 1)
}
const maxFreq = Array.from(items.entries()).sort((a, b) => b[1] - a[1])[0][0]
return maxFreq
}
В комментах уже правильно отметили, что в задаче про O(1) в методе "addToTail" после "else" не хватает переопределения "tail.next" на "node", а в методе " removeFromHead" проверки на пустую очередь после удаления и очистку хвоста: if (!this.#length) { this.tail = null; }
В статье поправить бы )
Большое спасибо за это видео! Очень круто! P.S. у тебя хороший вкус(я про твои футболки)!
огромное спасибо за такой прекрасный контент хотел просить вам об еще одной такой видеоролике ))
Как в тему, а главное вовремя, как раз готовлюсь к собесам
Обожаю подобное!
Более оптимальный вариант
function arraySubset(source, subset) {
let map = new Map();
for (let el of subset) {
const index = source.indexOf(el, map.get(el) || 0);
if (index >= 0) {
map.set(el, index + 1)
} else {
return false;
}
}
return true;
}
воооот то что надо🦴😅
Универсальная сумма покороче
function add() {
return typeof arguments[1] === "number"
? arguments[0] + arguments[1]
: add.bind(null, ...arguments)
}
Вот такое решение первой задачи, мне кажется более элегантным)
function isUnique(string){
let arrInput = Array.from(string)
let checked = [...new Set(arrInput)]
if(arrInput.length == checked.length)
{
console.log(true);
} else {
console.log(false);
}
}
Да суть то не в этом. Но ты прав так будет грамотнее)
arrInput.len ==checked.len ? True : false
function flatten(array) {
return array.flat(Infinity)
}
Вторая задача решается arr.flat(Infinity)
Как раз задача в том, чтоб сделать без встроенных методов)
Мне на собеседовании не одобрили такое решение) пришлось писать код)
@@VladilenMinin
function flatten(array) {
let result = [];
for (let i = 0, len = array.length; i < len; i += 1) {
(Array.isArray(array[i]))
? result.push(...flatten(array[i]))
: result.push(array[i]);
}
return result;
}
Эх,чувствую,что после этого видео ,количество задаваемых задач такого рода , неожиданно , сократиться,но спасибо за старание!
разве что увеличится
да не, они берут дефолтные в основном, так что база всегда будет актуально, + для себя практика хорошая, в плюсе останешься в любом случае
5 задание можно решить так:
const isStringRotated = (str1, str2) => {
return str1.split("").sort().join("") === str2.split("").sort().join("") ;
}
Одну и туже строку ( по символам) метод sort отсортирует абсолютно одинаково, поэтому можем конвертировать строку в массив отсортировать методом sort и сравнить.
Смотря как понять условие задачи. Является ли ротацией рандомная перестановка символов или только упорядоченная? Пример упорядоченной ротации: "abcdef" и "cdefab". Пример рандомной перестановки символов: "abcdef" и "cdbafe".
сортировка O(NLogN) а тут их 2, я думаю линейно побыстрее будет, не в угоду краткости и изящества
очень круто и все грамотно объясняется , СПАИБО!
В 7 задаче можно сделать set первого элемента, а потом в цикле делать set.add каждого элемента и сравнивать длину с первоначальным, если больше стала, то буквы лишние
Здравствуйте, подача материала очень хорошая. С удовольствием смотрю и учусь. В задаче про очередь O(1) вариант со связными списками не используется значение next в создаваемой node. Видимо просто пропущено, но из за этого решение не корректно отрабатывает.
Решить задачу "Плоский массив" можно проще:
let newStr = array.join()
return newStr.split(',').map(item => Number(item))
JSON.parse(`[${array.join()}]`)
😎
1 задача
function isUnique(str) {
return [...new Set(str.split('')].join('')
};
Большое спасибо, Владилен!
вторую вот так реализовал: const flatten = array => array.toString().split(',').map(i => Number(i))
Спасибо!, Вопрос по LinkedList - next ведь не указывает на следующий элемент, он всегда null?
в метод addToTail нужно добавить - this.#tail.next = node; а в removeFromHead - this.#head = this.#head.next;
Крутой видос, очень интересно было. Спасибо. Но есть одно маленькое предложение, было бы круто, если бы ты хоть вскользь упоминал где такие решения могут пригодиться. В смысле где может пригодиться узнавать развернута ли строка или сколько раз в строке встречается символ. Очень трудно вообразить такой сценарий.
const matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
function rotate(source) {
// todo
let x = [];
for (let i = 0; i < source.length; i++) {
x.push([matrix[2][i], matrix[1][i], matrix[0][i]]);
}
return x;
}
console.log(rotate(matrix));
а если массив будет 100 на 100 ?))
@@yoshimitsu7723 по идеи тоже должно развернуть, - 🙃 лень проверять
еще одно решение задачки "Является ли массив подмножеством другого массива":
function arraySubset(source, subset) {
if (subset.length > source.length) {
return false
}
return source.sort().join('').includes(subset.sort().join(''))
}
красиво но 2 сортировки и еще операция поиска O(NlogN+VlogV+...?)😁
По поводу 2 задачи с рекурсией я бы по проще это решил ( с учетом того что мы не смотрим на поддержку старых браузеров):
function flatten(arr) {
let res = arr.flat();
if (res.some(a => Array.isArray(a))) {
return flatten(res);
} else {
return res;
}
}
я так сделал : const flatten = array => array.toString().split(',').map(i => Number(i))
для проверки на подмножество можно использовать:
function arraySubset(source, subset) {
return source.sort().join().includes(subset.sort().join());
}
не будет работать, надо по символам сравнивать, а не целиком строку
Универсальное решение задачи на сумму (любое кол-во скобок и аргументов в них):
function add(...args) {
const parseArgs = (arr) => {
return arr.reduce((acc, arg) => {
if (Array.isArray(arg)) arg = parseArgs(arg)
if (!isNaN(+arg)) acc += +arg
return acc
}, 0)
}
let current = parseArgs(args)
const f = (...xArgs) => {
const tmpSum = parseArgs(xArgs)
current += tmpSum
return f
}
f.toNum = () => current
return f
}
console.log(add(1, 1, 1)(2)()(3, '2', 'ghf')('4')([2, 0])(-0)(NaN).toNum()) // 16
Владилен и Мурыч - спасибо вам за хорошую задачку! :)))
В 6 задаче наверно следовало бы упомянуть что удалять элементы из массива с помощью оператора delete на практике не рекомендуется, т.к. после такого удаления длина массива не меняется, что может привести к путанице в дальнейшей разработке. В подобном случае наверно стоит использовать метод slice.
Было интересно посмотреть. Респект!
Спасибо! Очень полезное видео))
Вариант первой задачки без циклов сравнений:
function isUnique(string) {
const setStr = [...new Set([...string])].join('');
if (setStr === string) {
return false;
}
return true;
}
Посмотри, я предложил 3 решения. Но круто, что сам подумал про Set!
@@VladilenMinin точно 😅
const {log} = console; От чела который на codewars 250 место занимает. (Подсмотрел)
А по времени, как узнать сколько код выполняется как на 1:45:00
Над кодом
log(time)
под кодом
log(end)
Вторая задача изи решается через stack. Думаю стоит рассказывать новичкам также и про структуры данных и их применение.
16:10 - Как мы можем пробегаться по вызову функции flat, как по массиву? Я имею ввиду что в константе flat у нас лежит вызов функции flatten(array[i]). Выглядит это след. образом: const flat = flatten(array[i]). И мы пробегаемся циклом for(let j = 0; j
дак flatten возвращает "return res"
тоже долго въезжал и не понимал именно это, с какого хера мы продолжаем идти по циклу for(let j = 0; j
function isUnique(string) {
const arr = []
let result = true
Array.from(string).forEach(item => arr.includes(item) ? result = false : arr.push(item))
return result
}
Спасибо за материал!
А где в LinkedList собсно линковка? next всегда null
Большое спасибо! Видео супер
вот такой огород нагородил )) работает хреновина )
function isUnique(string) {
let result = true
const arr = string.split('')
for(let i = 0; i < arr.length; i += 1){
let count = 0
arr.forEach(item => {
if(item === arr[i]){
count += 1
if(count > 1){
result = false
}
}
})
}
return result
}
втора задача про плоский массив решается одной строчкой через flat(Infinity)
Спасибо большое тебе добрый человек!!!
Мне кажется в задачке про подсчет повторяющихся строк в массиве не до конца выполняется условие задания. В вашем коде, если я все правильно понял, из массива {a, b, b, a} программа вернет - b. А исходя из условия должна быть возвращена первая встречающаяся - это "а". В последнем ифе на 3 итерации вышепредложенного массива в maxFreqStr будет записана b и в 4ой итерации с кодом в ифе мы получим 2 > 2 и программа вернет b.
я добавил такую строку, чтоб вернуть "a":
maxFStr = Object.keys(map).find(key => map[key] === maxF)
return maxFStr
Мега суперрр!!!
К сожалению, в решении многих задач используют неоптимальные с точки зрения сложности и памяти алгоритмы. А так же используются структуры данных, которые заменяют требуемые алгоритмы. А именно их просят продемонстрировать на собеседованиях и такие ответы не принимают. Говорю по опыту прохождения интервью в крупных компаниях. Но в общем и целом - спасибо за материал.
Вы абсолютно правы. Например, в задаче про скобочную последовательность ждут скорее, что вы произнесете заветное слово "стек" вместо "очередь".
Спасибо за эти бесплатные уроки и разборы, жаль нет бабла пойти к вам на курсы =)
Спасибо за ролик!
6 алгоритм на плюсах не очень идеален, там пришлось бы наверное итераторы хранить в unordered_map и через if его инициализировать если через std::find найдем элемент и потом при повторе уже в ветке else будем брать уже итератор из map в find-е, как-то так на плюсах; либо без итераторов и find (дабы исключить работу с библиотекой стандартных алгоритмов) пришлось бы хранить по ключу индекса элемент который будем игнорировать, или... можно не удалять элемент(чтобы если это vector не перестраивать всю последовательность) заменять его на элемент какой-то🤔либо заново создавать vector :)) сорри, готовлюсь не к тому языку по алгоритмам))
2-задание. Просто, так мало вложенности получается)
function flatten(array, arr) {
for (const elem of array) {
if (Array.isArray(elem)) flatten(elem, arr)
else arr.push(elem)
}
return arr
}
это же не будет работать, и что при первом вызове передаётся вторым аргументом?
@@aleksandr2245 как не будет работать, запускал? второй аргумент [ ]
@@ЭзизК а, теперь понял, спасибо
function deepEqual(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
Не всегда сработает корректно, тк не гарантирует одинаковую последовательность для вложенных объектов и их ключей
Спасибо за видео! Кто мне скажет, по чему задачи на javascript в основном решают готовыми методами? Мне кажется, что когда решают в ручную, то лучше понимаешь, что и как.
Я второй и я сотрю ваш курс по JavaScript и уже почти закончил
2я задача: flat(Infinity) и всё)
тоже так решил, зачем так мучаться))))
Я могу ошибаться, но в задаче №11 про связанный список (LinkedList) косяк. При добавлении элементов не ставится ссылка на следующий элемент, т.е. next = null всегда. В итоге, если добавить 3 элемента, а затем удалить 2 элемента, то при удалении второго элемента получим ошибку, т.к. при удалении первого элемента мы переключились на null
Решение 12 задачи (глубокое сравнение) - какой-то трэш, если без мата. Вот решение в 1 строку:
function deepEqual (a, b) {
return JSON.stringify(a) === JSON.stringify(b)
}
Задача 13.
Судя по ссылке на определение последовательности: первые два числа равны 0 и 1, а каждое последующее число равно сумме двух предыдущих чисел.
Поэтому ПЕРВОЕ число должно быть равно 0, а не 1 (в видео первое число равно 1). Т.е.:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, …
Крутое видео, спасибо!