TGViewer
Channel Public Channel
JavaScript | LeetCode

JavaScript | LeetCode

@easy_frontend_task

Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy

Контакт для рекламы: @sendme_ads
Subscribers
8.32K
Photos
248
Videos
0
Links
1.4K

Showing posts older than #2191 · Back to latest

Older Posts 20 shown
Post #2189 745
Задача: 1233. Remove Sub-Folders from the Filesystem
Сложность: medium

Если дан список папок folder, верните папки после удаления всех вложенных папок в этих папках. Вы можете вернуть ответ в любом порядке. Если папка[i] находится внутри другой папки[j], она называется ее вложенной папкой. Формат пути - это одна или несколько скомбинированных строк вида: '/', за которой следует одна или несколько строчных английских букв. Например, "/leetcode" и "/leetcode/problems" являются допустимыми путями, а пустая строка и "/" - нет.

Пример:
Input: folder = ["/a","/a/b","/c/d","/c/d/e","/c/f"]
Output: ["/a","/c/d","/c/f"]


👨‍💻 Алгоритм:

1⃣Сортировка папок:
Сначала отсортируем список путей в лексикографическом порядке. Это обеспечит, что при обходе отсортированного списка мы всегда будем проверять родительскую папку перед вложенными папками.

2⃣Фильтрация вложенных папок:
Будем использовать переменную для отслеживания текущей родительской папки.

3⃣При проходе по отсортированному списку проверим, является ли текущий путь вложенной папкой для отслеживаемой родительской папки. Если нет, обновим отслеживаемую папку и добавим ее в результирующий список.

😎 Решение:
var removeSubfolders = function(folder) {
folder.sort();
let result = [];
let parent = "";

for (let path of folder) {
if (!parent || !path.startsWith(parent + "/")) {
parent = path;
result.push(path);
}
}

return result;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2186 798
Задача: 914. X of a Kind in a Deck of Cards


Вам дан целочисленный массив deck, где deck[i] - число, написанное на i-й карте. Разделите карты на одну или несколько групп так, чтобы: в каждой группе было ровно x карт, где x > 1, и на всех картах в одной группе было написано одно и то же целое число. Верните true, если такое разделение возможно, или false в противном случае.

Пример:
Input: deck = [1,2,3,4,4,3,2,1]
Output: true


👨‍💻 Алгоритм:

1⃣Создать словарь для подсчета частоты каждого числа в массиве deck.

2⃣Найти наибольший общий делитель (НОД) всех частот.

3⃣Проверить, больше ли НОД 1, чтобы определить, можно ли разделить карты на группы.

😎 Решение:
var hasGroupsSizeX = function(deck) {
const count = deck.reduce((acc, num) => {
acc[num] = (acc[num] || 0) + 1;
return acc;
}, {});

const freqValues = Object.values(count);
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
const g = freqValues.reduce((acc, val) => gcd(acc, val));

return g > 1;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2184 831
Задача: 736. Parse Lisp Expression
Сложность: hard

Нам дан массив asteroids, состоящий из целых чисел, представляющих астероиды в ряд. Для каждого астероида абсолютное значение обозначает его размер, а знак - направление движения (положительное - вправо, отрицательное - влево). Каждый астероид движется с одинаковой скоростью. Определите состояние астероидов после всех столкновений. Если два астероида столкнутся, меньший из них взорвется. Если оба одинакового размера, то взорвутся оба. Два астероида, движущиеся в одном направлении, никогда не встретятся.

Пример:
Input: expression = "(let x 2 (mult x (let x 3 y 4 (add x y))))"
Output: 14


👨‍💻 Алгоритм:

1⃣Определите функцию для оценки выражений.

2⃣Используйте рекурсивный подход для обработки различных типов выражений (let, add, mult, и переменных).

3⃣Используйте словарь для отслеживания значений переменных с учетом области видимости.

😎 Решение:
class Solution {
evaluate(expression) {
const evaluate = (expression, env) => {
if (!expression.startsWith('(')) {
if (isNaN(expression)) {
return env[expression];
}
return parseInt(expression);
}

const tokens = tokenize(expression);
if (tokens[0] === 'let') {
for (let i = 1; i < tokens.length - 2; i += 2) {
env[tokens[i]] = evaluate(tokens[i + 1], env);
}
return evaluate(tokens[tokens.length - 1], env);
} else if (tokens[0] === 'add') {
return evaluate(tokens[1], env) + evaluate(tokens[2], env);
} else if (tokens[0] === 'mult') {
return evaluate(tokens[1], env) * evaluate(tokens[2], env);
}
};

const tokenize = (expression) => {
let tokens = [];
let token = '';
let parens = 0;
for (let char of expression) {
if (char === '(') {
parens++;
if (parens === 1) {
continue;
}
} else if (char === ')') {
parens--;
if (parens === 0) {
tokens.push(tokenize(token));
token = '';
continue;
}
} else if (char === ' ' && parens === 1) {
if (token) {
tokens.push(token);
token = '';
}
continue;
}
token += char;
}
if (token) {
tokens.push(token);
}
return tokens;
};

return evaluate(expression, {});
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2182 861
Задача: 1026. Maximum Difference Between Node and Ancestor
Сложность: medium

Учитывая корень бинарного дерева, найдите максимальное значение v, для которого существуют различные вершины a и b, где v = |a.val - b.val| и a является предком b. Вершина a является предком b, если: любой ребенок a равен b или любой ребенок a является предком b.

Пример:
Input: root = [8,3,10,1,6,null,14,null,null,4,7,13]
Output: 7


👨‍💻 Алгоритм:

1⃣Рекурсивный обход дерева:
Используйте рекурсивную функцию для обхода дерева. Передавайте минимальное и максимальное значения, встреченные на пути от корня к текущему узлу.

2⃣Обновление максимальной разницы:
При посещении каждого узла обновляйте минимальное и максимальное значения. Вычисляйте разницу между текущим значением узла и минимальным и максимальным значениями на пути. Обновляйте максимальную разницу, если текущая разница больше.

3⃣Рекурсивный вызов для детей:
Рекурсивно вызывайте функцию для левого и правого поддерева, передавая обновленные минимальное и максимальное значения.

😎 Решение:
class TreeNode {
constructor(val = 0, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}

class Solution {
maxAncestorDiff(root) {
const dfs = (node, minVal, maxVal) => {
if (!node) return maxVal - minVal;
minVal = Math.min(minVal, node.val);
maxVal = Math.max(maxVal, node.val);
const left = dfs(node.left, minVal, maxVal);
const right = dfs(node.right, minVal, maxVal);
return Math.max(left, right);
};
return dfs(root, root.val, root.val);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2179 755
Задача: 340. Longest Substring with At Most K Distinct Characters
Сложность: medium

Дана строка s и целое число k. Верните длину самой длинной подстроки s, которая содержит не более k различных символов.

Пример:
Input: n = 27
Output: true
Explanation: 27 = 3^3


👨‍💻 Алгоритм:

1⃣Инициализация
Используйте два указателя (left и right) для отслеживания текущего окна в строке. Создайте словарь для отслеживания количества каждого символа в текущем окне. Инициализируйте переменные для хранения максимальной длины подстроки (max_length).

2⃣Раздвижение окна
Перемещайте правый указатель (right) по строке и обновляйте словарь. Если количество различных символов в словаре превышает k, перемещайте левый указатель (left) вправо, уменьшая счетчик символов, пока количество различных символов снова не станет меньше или равно k.

3⃣Обновление максимальной длины
На каждом шаге проверяйте и обновляйте максимальную длину подстроки, если текущее окно содержит не более k различных символов. В конце верните максимальную длину подстроки.

😎 Решение:
var lengthOfLongestSubstringKDistinct = function(s, k) {
let left = 0, right = 0;
const charCount = new Map();
let maxLength = 0;

while (right < s.length) {
charCount.set(s[right], (charCount.get(s[right]) || 0) + 1);
while (charCount.size > k) {
charCount.set(s[left], charCount.get(s[left]) - 1);
if (charCount.get(s[left]) === 0) {
charCount.delete(s[left]);
}
left++;
}
maxLength = Math.max(maxLength, right - left + 1);
right++;
}

return maxLength;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2177 906
Задача: 1030. Matrix Cells in Distance Order
Сложность: easy

Вам даны четыре целых числа row, cols, rCenter и cCenter. Имеется матрица rows x cols, и вы находитесь на ячейке с координатами (rCenter, cCenter). Верните координаты всех ячеек в матрице, отсортированные по их расстоянию от (rCenter, cCenter) от наименьшего расстояния до наибольшего. Вы можете вернуть ответ в любом порядке, удовлетворяющем этому условию. Расстояние между двумя ячейками (r1, c1) и (r2, c2) равно |r1 - r2| + |c1 - c2|.

Пример:
Input: rows = 1, cols = 2, rCenter = 0, cCenter = 0
Output: [[0,0],[0,1]]


👨‍💻 Алгоритм:

1⃣Инициализация и вычисление расстояний:
Создайте список для хранения всех координат ячеек в матрице.
Вычислите расстояние Манхэттена от каждой ячейки до центра и добавьте пару (расстояние, координаты) в список.

2⃣Сортировка списка:
Отсортируйте список по расстоянию в порядке возрастания.

3⃣Извлечение координат:
Извлеките координаты из отсортированного списка и верните их.

😎 Решение:
var allCellsDistOrder = function(rows, cols, rCenter, cCenter) {
const cells = [];

for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const distance = Math.abs(r - rCenter) + Math.abs(c - cCenter);
cells.push([distance, r, c]);
}
}

cells.sort((a, b) => a[0] - b[0]);

return cells.map(cell => [cell[1], cell[2]]);
};


Ставь 👍 и забирай 📚 Базу знаний
  • 👍 2
Post #2175 1.05K
Пожизненная PRO подписка на easyoffer по цене одного года.

Акция до 20 февраля. Покупаешь сейчас один раз – пользуешься всю жизнь без лимита, включая все будущие функции.

Запланированные новые фичи на ближайшие пол года:
1. Агрегатор вакансий
2. Улучшение резюме, чтобы проходить ATS системы
3. Генерация уникального резюме и сопроводительного письма под вакансию

Покупай на https://easyoffer.ru/
Post #2173 883
Задача: 1358. Number of Substrings Containing All Three Characters
Сложность: medium

Дана строка s, состоящая только из символов a, b и c.

Верните количество подстрок, содержащих хотя бы одно вхождение всех этих символов a, b и c.

Пример:
Input: s = "abc"
Output: 1


👨‍💻 Алгоритм:

1⃣Инициализация указателей и счетчиков:
Создайте три указателя i, j, и count для отслеживания текущего положения в строке и подсчета подстрок. Используйте словарь для подсчета вхождений символов a, b, и c.

2⃣Расширение окна:
Перемещайте правый указатель j по строке и увеличивайте счетчики символов в словаре. Как только все три символа (a, b, и c) присутствуют в текущем окне, начинайте уменьшать левый указатель i.

3⃣Уменьшение окна и подсчет подстрок:
Для каждого сдвига i вправо, проверяйте наличие всех символов в текущем окне. Если все символы присутствуют, добавьте количество подстрок, заканчивающихся в позиции j, к общему счету. Сдвигайте i вправо до тех пор, пока условие выполнения не нарушится.
Верните итоговое количество подстрок.

😎 Решение:
var numberOfSubstrings = function(s) {
let count = 0;
let charCount = { 'a': 0, 'b': 0, 'c': 0 };
let i = 0;

for (let j = 0; j < s.length; j++) {
charCount[s[j]]++;

while (charCount['a'] > 0 && charCount['b'] > 0 && charCount['c'] > 0) {
count += s.length - j;
charCount[s[i]]--;
i++;
}
}

return count;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2171 691
Задача: 1048. Longest String Chain
Сложность: easy

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

Например, "abc" является предшественником "abac", а "cba" не является предшественником "bcad". Цепочка слов - это последовательность слов [word1, word2, ..., wordk] с k >= 1, где word1 является предшественником word2, word2 является предшественником word3 и так далее. Одиночное слово тривиально является цепочкой слов с k == 1. Верните длину самой длинной возможной цепочки слов со словами, выбранными из заданного списка слов.

Пример:
Input: words = ["a","b","ba","bca","bda","bdca"]
Output: 4


👨‍💻 Алгоритм:

1⃣Отсортируй список слов по длине.

2⃣Используй динамическое программирование для вычисления длины самой длинной цепочки для каждого слова.

3⃣Верни максимальную длину среди всех цепочек.

😎 Решение:
function longestStrChain(words) {
words.sort((a, b) => a.length - b.length);
let dp = new Map();
let longestChain = 1;

for (let word of words) {
dp.set(word, 1);
for (let i = 0; i < word.length; i++) {
let predecessor = word.slice(0, i) + word.slice(i + 1);
if (dp.has(predecessor)) {
dp.set(word, Math.max(dp.get(word), dp.get(predecessor) + 1));
}
}
longestChain = Math.max(longestChain, dp.get(word));
}

return longestChain;
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2170 607
Задача: 284. Peeking Iterator
Сложность: medium

Создайте итератор, который поддерживает операцию peek (просмотр следующего элемента) на существующем итераторе, помимо операций hasNext (проверка наличия следующего элемента) и next (получение следующего элемента).
Реализуйте класс PeekingIterator:
PeekingIterator(Iterator<int> nums): Инициализирует объект с заданным итератором целых чисел.
int next(): Возвращает следующий элемент в массиве и перемещает указатель на следующий элемент.
boolean hasNext(): Возвращает true, если в массиве еще есть элементы.
int peek(): Возвращает следующий элемент в массиве без перемещения указателя.

Пример:
Input
["PeekingIterator", "next", "peek", "next", "next", "hasNext"]
[[[1, 2, 3]], [], [], [], [], []]
Output
[null, 1, 2, 2, 3, false]

Explanation
PeekingIterator peekingIterator = new PeekingIterator([1, 2, 3]); // [1,2,3]
peekingIterator.next(); // return 1, the pointer moves to the next element [1,2,3].
peekingIterator.peek(); // return 2, the pointer does not move [1,2,3].
peekingIterator.next(); // return 2, the pointer moves to the next element [1,2,3]
peekingIterator.next(); // return 3, the pointer moves to the next element [1,2,3]
peekingIterator.hasNext(); // return False


👨‍💻 Алгоритм:

1⃣Инициализация итератора:
В конструкторе класса PeekingIterator инициализируйте итератор и проверьте, есть ли следующий элемент. Если есть, установите его как next, иначе установите next в null.

2⃣Операция peek:
Метод peek возвращает значение next, не перемещая указатель итератора.

3⃣Операции next и hasNext:
Метод next возвращает текущее значение next, обновляет next к следующему элементу в итераторе и перемещает указатель итератора. Если нет следующего элемента, бросает исключение NoSuchElementException.
Метод hasNext возвращает true, если next не равно null, и false в противном случае.

😎 Решение:
class PeekingIterator {
constructor(iterator) {
this.iterator = iterator;
this.nextElement = iterator.hasNext() ? iterator.next() : null;
}

next() {
const currentElement = this.nextElement;
this.nextElement = this.iterator.hasNext() ? this.iterator.next() : null;
return currentElement;
}

hasNext() {
return this.nextElement !== null;
}

peek() {
return this.nextElement;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2169 609
Задача: 1025. Divisor Game
Сложность: easy

Алиса и Боб играют в игру по очереди, причем Алиса начинает первой. Изначально на доске мелом написано число n. В свой ход каждый игрок делает ход, состоящий из: выбора любого x при 0 < x < n и n % x == 0. Замены числа n на доске на n - x. Также, если игрок не может сделать ход, он проигрывает игру. Возвращается true тогда и только тогда, когда Алиса выигрывает игру, предполагая, что оба игрока играют оптимально.

Пример:
Input: n = 2
Output: true


👨‍💻 Алгоритм:

1⃣Определение выигрыша:
Заметим, что если число n четное, Алиса всегда выигрывает, потому что она может уменьшить n на 1, и оставить Боба с нечетным числом.
Если число n нечетное, Алиса всегда проигрывает, потому что Боб может уменьшить n на 1, и оставить Алису с четным числом.

2⃣Проверка четности числа:
Проверяем, четное ли число n. Если n четное, возвращаем true, если нечетное, возвращаем false.

3⃣Возврат результата:
Возвращаем результат в зависимости от четности числа n.

😎 Решение:
class Solution {
divisorGame(n) {
return n % 2 === 0;
}
}


Ставь 👍 и забирай 📚 Базу знаний
  • 💊 1
Post #2168 651
Задача: 978. Longest Turbulent Subarray
Сложность: medium

Дан целочисленный массив arr, верните длину максимального турбулентного подмассива массива arr.

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

Более формально, подмассив [arr[i], arr[i + 1], ..., arr[j]] массива arr считается турбулентным тогда и только тогда, когда:

Для всех i <= k < j:
arr[k] > arr[k + 1], когда k нечетное, и
arr[k] < arr[k + 1], когда k четное.
Или, для всех i <= k < j:
arr[k] > arr[k + 1], когда k четное, и
arr[k] < arr[k + 1], когда k нечетное.

Пример:
Input: arr = [9,4,2,10,7,8,8,1,9]
Output: 5
Explanation: arr[1] > arr[2] < arr[3] > arr[4] < arr[5]


👨‍💻 Алгоритм:

1⃣Сканируйте массив слева направо. Используйте переменные для отслеживания начала текущего блока и максимальной длины турбулентного подмассива.

2⃣Если достигли конца блока (последний элемент или текущий элемент не соответствует условию чередования), зафиксируйте длину этого блока как потенциальный ответ и установите начало нового блока на следующий элемент.

3⃣Повторяйте шаг 2 до конца массива и верните максимальную длину турбулентного подмассива.

😎 Решение:
var maxTurbulenceSize = function(A) {
const N = A.length;
let ans = 1;
let anchor = 0;

for (let i = 1; i < N; ++i) {
const c = Math.sign(A[i - 1] - A[i]);
if (c === 0) {
anchor = i;
} else if (i === N - 1 || c * Math.sign(A[i] - A[i + 1]) !== -1) {
ans = Math.max(ans, i - anchor + 1);
anchor = i;
}
}

return ans;
};


Ставь 👍 и забирай 📚 Базу знаний
  • 👍 1
Post #2167 602
Задача: 599. Minimum Index Sum of Two Lists
Сложность: easy

Даны два массива строк list1 и list2, необходимо найти общие строки с наименьшей суммой индексов.
Общая строка - это строка, которая появляется и в list1, и в list2.
Общая строка с наименьшей суммой индексов - это общая строка, такая, что если она появилась в list1[i] и list2[j], то i + j должно быть минимальным значением среди всех других общих строк.
Верните все общие строки с наименьшей суммой индексов. Верните ответ в любом порядке.

Пример:
Input: list1 = ["Shogun","Tapioca Express","Burger King","KFC"], list2 = ["Piatti","The Grill at Torrey Pines","Hungry Hunter Steakhouse","Shogun"]
Output: ["Shogun"]
Explanation: The only common string is "Shogun".


👨‍💻 Алгоритм:

1⃣Для каждой строки из list1, сравниваем её с каждой строкой из list2, обходя весь список list2. Используем хэш-таблицу map, которая содержит элементы в виде (сумма: список строк). Здесь сумма относится к сумме индексов совпадающих элементов, а список строк соответствует списку совпадающих строк, чья сумма индексов равна этой сумме.

2⃣Во время сравнений, когда находится совпадение строки на i-м индексе из list1 и j-м индексе из list2, создаём запись в map, соответствующую сумме i + j, если такая запись ещё не существует. Если запись с этой суммой уже существует, добавляем текущую строку в список строк, соответствующих сумме i + j.

3⃣В конце обходим ключи в map и находим список строк, соответствующих ключу с минимальной суммой.

😎 Решение:
var findRestaurant = function(list1, list2) {
let map = new Map();
for (let i = 0; i < list1.length; i++) {
for (let j = 0; j < list2.length; j++) {
if (list1[i] === list2[j]) {
if (!map.has(i + j)) {
map.set(i + j, []);
}
map.get(i + j).push(list1[i]);
}
}
}
let minIndexSum = Math.min(...map.keys());
return map.get(minIndexSum);
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2166 511
Задача: 641. Design Circular Deque
Сложность: medium

Разработайте свою реализацию круговой двусторонней очереди (deque). Реализуйте класс MyCircularDeque: MyCircularDeque(int k) Инициализирует deque с максимальным размером k. boolean insertFront() Добавляет элемент в переднюю часть Deque. Возвращает true, если операция прошла успешно, или false в противном случае. boolean insertLast() Добавляет элемент в заднюю часть Deque. Возвращает true, если операция выполнена успешно, или false в противном случае. boolean deleteFront() Удаляет элемент из передней части Deque. Возвращает true, если операция прошла успешно, или false в противном случае. boolean deleteLast() Удаляет элемент из задней части Deque. Возвращает true, если операция прошла успешно, или false в противном случае. int getFront() Возвращает передний элемент из Deque. Возвращает -1, если Deque пуст. int getRear() Возвращает последний элемент из Deque. Возвращает -1, если Deque пуст. boolean isEmpty() Возвращает true, если Deque пуст, или false в противном случае. boolean isFull() Возвращает true, если Deque полон, или false в противном случае.

Пример:
Input
["MyCircularDeque", "insertLast", "insertLast", "insertFront", "insertFront", "getRear", "isFull", "deleteLast", "insertFront", "getFront"]
[[3], [1], [2], [3], [4], [], [], [], [4], []]
Output
[null, true, true, true, false, 2, true, true, true, 4]


👨‍💻 Алгоритм:

1⃣Инициализация и проверка состояний
Реализуйте конструктор для инициализации кольцевой двусторонней очереди заданного размера и методы для проверки пустоты и полноты очереди.

2⃣Операции вставки
Реализуйте методы вставки элементов в переднюю и заднюю части очереди с учетом кольцевой структуры.

3⃣Операции удаления
Реализуйте методы удаления элементов из передней и задней частей очереди с учетом кольцевой структуры и методы для получения переднего и заднего элементов очереди.

😎 Решение:
var MyCircularDeque = function(k) {
this.k = k;
this.deque = new Array(k);
this.front = 0;
this.rear = 0;
this.size = 0;
};

MyCircularDeque.prototype.insertFront = function(value) {
if (this.isFull()) return false;
this.front = (this.front - 1 + this.k) % this.k;
this.deque[this.front] = value;
this.size++;
return true;
};

MyCircularDeque.prototype.insertLast = function(value) {
if (this.isFull()) return false;
this.deque[this.rear] = value;
this.rear = (this.rear + 1) % this.k;
this.size++;
return true;
};

MyCircularDeque.prototype.deleteFront = function() {
if (this.isEmpty()) return false;
this.front = (this.front + 1) % this.k;
this.size--;
return true;
};

MyCircularDeque.prototype.deleteLast = function() {
if (this.isEmpty()) return false;
this.rear = (this.rear - 1 + this.k) % this.k;
this.size--;
return true;
};

MyCircularDeque.prototype.getFront = function() {
if (this.isEmpty()) return -1;
return this.deque[this.front];
};

MyCircularDeque.prototype.getRear = function() {
if (this.isEmpty()) return -1;
return this.deque[(this.rear - 1 + this.k) % this.k];
};

MyCircularDeque.prototype.isEmpty = function() {
return this.size === 0;
};

MyCircularDeque.prototype.isFull = function() {
return this.size === this.k;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2165 588
Задача: 663. Equal Tree Partition
Сложность: medium

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

Пример:
Input: root = [5,10,10,null,null,2,3]
Output: true


👨‍💻 Алгоритм:

1⃣Вычисление общей суммы:
Напишите функцию для вычисления общей суммы всех узлов дерева.

2⃣Проверка возможности разделения:
Напишите функцию, чтобы рекурсивно проверить, может ли поддерево быть равно половине общей суммы. Если такое поддерево найдено, значит дерево можно разделить на две части с равными суммами.

3⃣Валидация и возврат результата:
Проверьте, что общая сумма четная (так как только в этом случае возможно её разделение на две равные части), и используйте функцию проверки поддерева, чтобы определить, можно ли разделить дерево на две части с равными суммами.

😎 Решение:
function TreeNode(val, left, right) {
this.val = (val===undefined ? 0 : val)
this.left = (left===undefined ? null : left)
this.right = (right===undefined ? null : right)
}

var checkEqualTree = function(root) {
const totalSum = sumTree(root);
if (totalSum % 2 !== 0) return false;
const target = totalSum / 2;
return checkSubtreeSum(root, target, root);
};

function sumTree(node) {
if (!node) return 0;
return node.val + sumTree(node.left) + sumTree(node.right);
}

function checkSubtreeSum(node, target, root) {
if (!node) return false;
if (node !== root && sumTree(node) === target) {
return true;
}
return checkSubtreeSum(node.left, target, root) || checkSubtreeSum(node.right, target, root);
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2164 672
Задача: 1406. Stone Game III
Сложность: hard

Алиса и Боб продолжают свои игры с кучами камней. Камни расположены в ряд, и каждый камень имеет ассоциированное значение, которое представлено целым числом в массиве stoneValue.
Алиса и Боб ходят по очереди, начиная с Алисы. В свой ход каждый игрок может взять 1, 2 или 3 камня из первых оставшихся камней в ряду.

Счет каждого игрока равен сумме значений взятых камней. Изначально счет каждого игрока равен 0.
Цель игры — закончить с наивысшим счетом, и победителем становится игрок с наивысшим счетом, при этом возможна ничья. Игра продолжается, пока все камни не будут взяты.

Предположим, что Алиса и Боб играют оптимально.
Верните "Alice", если Алиса выиграет, "Bob", если выиграет Боб, или "Tie", если они закончат игру с одинаковым счетом.

Пример:
Input: stoneValue = [1,2,3,7]
Output: "Bob"
Explanation: Alice will always lose. Her best move will be to take three piles and the score become 6. Now the score of Bob is 7 and Bob wins.


👨‍💻 Алгоритм:

1⃣Инициализируйте массив dp размером n+1 и установите dp[n] в 0.

2⃣Итеративно обновляйте dp[i] для всех i от n-1 до 0, вычисляя максимальную разницу в баллах, которые могут получить игроки при оптимальной игре.

3⃣Определите победителя, сравнивая dp[0] с 0: если больше, победит Алиса; если меньше, победит Боб; если равно, будет ничья.

😎 Решение:
class Solution {
stoneGameIII(stoneValue) {
const n = stoneValue.length;
const dp = new Array(n + 1).fill(0);
for (let i = n - 1; i >= 0; i--) {
dp[i] = stoneValue[i] - dp[i + 1];
if (i + 2 <= n) {
dp[i] = Math.max(dp[i], stoneValue[i] + stoneValue[i + 1] - dp[i + 2]);
}
if (i + 3 <= n) {
dp[i] = Math.max(dp[i], stoneValue[i] + stoneValue[i + 1] + stoneValue[i + 2] - dp[i + 3]);
}
}
if (dp[0] > 0) {
return "Alice";
} else if (dp[0] < 0) {
return "Bob";
} else {
return "Tie";
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2163 658
Задача: 227. Basic Calculator II
Сложность: medium

Дана строка s, представляющая выражение. Вычислите это выражение и верните его значение.
Целочисленное деление должно округляться к нулю.
Вы можете предположить, что данное выражение всегда является допустимым. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].
Примечание: Запрещено использовать какие-либо встроенные функции, которые вычисляют строки как математические выражения, такие как eval().

Пример:
Input: s = "3+2*2"
Output: 7


👨‍💻 Алгоритм:

1⃣Вместо использования стека, используем переменную lastNumber для отслеживания значения последнего вычисленного выражения.

2⃣Если операция сложения (+) или вычитания (-), добавляем lastNumber к результату вместо того, чтобы помещать его в стек. Текущее значение currentNumber будет обновлено на lastNumber для следующей итерации.

3⃣Если операция умножения (*) или деления (/), вычисляем выражение lastNumber * currentNumber и обновляем lastNumber с результатом выражения. Это значение будет добавлено к результату после сканирования всей строки.

😎 Решение:
class Solution {
calculate(s) {
let length = s.length;
if (length === 0) return 0;
let currentNumber = 0, lastNumber = 0, result = 0;
let sign = '+';

for (let i = 0; i < length; i++) {
let currentChar = s[i];
if (!isNaN(currentChar) && currentChar !== ' ') {
currentNumber = (currentNumber * 10) + parseInt(currentChar);
}
if (isNaN(currentChar) && currentChar !== ' ' || i === length - 1) {
if (sign === '+' || sign === '-') {
result += lastNumber;
lastNumber = (sign === '+') ? currentNumber : -currentNumber;
} else if (sign === '*') {
lastNumber *= currentNumber;
} else if (sign === '/') {
lastNumber /= currentNumber;
}
sign = currentChar;
currentNumber = 0;
}
}
result += lastNumber;
return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2162 661
Задача: 924. Minimize Malware Spread
Сложность: hard

Вам дана сеть из n узлов, представленная в виде графа с матрицей смежности n x n, где i-й узел непосредственно связан с j-м узлом, если graph[i][j] == 1. Некоторые узлы изначально заражены вредоносным ПО. Если два узла соединены напрямую и хотя бы один из них заражен вредоносным ПО, то оба узла будут заражены вредоносным ПО. Такое распространение вредоносного ПО будет продолжаться до тех пор, пока не останется ни одного узла, который можно было бы заразить таким образом. Предположим, что M(initial) - это конечное число узлов, зараженных вредоносным ПО, во всей сети после прекращения распространения вредоносного ПО. Мы удалим из initial ровно один узел. Верните тот узел, удаление которого минимизирует M(initial). Если можно удалить несколько узлов, чтобы минимизировать M(initial), верните такой узел с наименьшим индексом. Обратите внимание, что если узел был удален из начального списка зараженных узлов, он все равно может быть заражен позже из-за распространения вредоносного ПО.

Пример:
Input: arr = [1,1,2,2,3,3,4,4,5,5], target = 8
Output: 20


👨‍💻 Алгоритм:

1⃣Определить количество зараженных узлов после распространения вредоносного ПО для исходного списка initial.

2⃣Для каждого узла в initial удалить его и вычислить количество зараженных узлов после распространения вредоносного ПО.

3⃣Найти узел, удаление которого минимизирует количество зараженных узлов. Если есть несколько таких узлов, выбрать узел с наименьшим индексом.

😎 Решение:
var minMalwareSpread = function(graph, initial) {
const dfs = (node, infected) => {
for (let neighbor = 0; neighbor < graph.length; neighbor++) {
if (graph[node][neighbor] === 1 && !infected.has(neighbor)) {
infected.add(neighbor);
dfs(neighbor, infected);
}
}
};

const n = graph.length;
const initialSet = new Set(initial);
initial.sort((a, b) => a - b);
let minInfected = Infinity;
let bestNode = initial[0];

for (const node of initial) {
const infected = new Set(initialSet);
infected.delete(node);
for (const i of initialSet) {
if (i !== node) {
dfs(i, infected);
}
}
if (infected.size < minInfected) {
minInfected = infected.size;
bestNode = node;
}
}

return bestNode;
};


Ставь 👍 и забирай 📚 Базу знаний
  • 👍 1
Post #2161 743
Задача: 1474. Delete N Nodes After M Nodes of a Linked List
Сложность: easy

Вам дано начало связанного списка и два целых числа m и n.

Пройдите по связанному списку и удалите некоторые узлы следующим образом:
Начните с головы как текущего узла.
Сохраните первые m узлов, начиная с текущего узла.
Удалите следующие n узлов.
Продолжайте повторять шаги 2 и 3, пока не достигнете конца списка.
Верните голову изменённого списка после удаления указанных узлов.

Пример:
Input: head = [1,2,3,4,5,6,7,8,9,10,11,12,13], m = 2, n = 3
Output: [1,2,6,7,11,12]
Explanation: Keep the first (m = 2) nodes starting from the head of the linked List (1 ->2) show in black nodes.
Delete the next (n = 3) nodes (3 -> 4 -> 5) show in read nodes.
Continue with the same procedure until reaching the tail of the Linked List.
Head of the linked list after removing nodes is returned.


👨‍💻 Алгоритм:

1⃣Инициализация указателей:
Инициализируйте currentNode на голову связанного списка. Этот указатель будет использоваться для линейного прохода по каждому узлу списка.
Инициализируйте lastMNode на голову связанного списка.

2⃣Итерация по списку:
Итеративно удаляйте n узлов после m узлов, продолжая до конца списка.
Проходите m узлов, обновляя lastMNode на текущий узел. После m итераций lastMNode указывает на m-й узел.
Продолжайте итерацию по n узлам.

3⃣Удаление узлов:
Чтобы удалить n узлов, измените указатель next у lastMNode, чтобы он указывал на currentNode после пропуска n узлов.

😎 Решение:
function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}

var deleteNodes = function(head, m, n) {
let currentNode = head;
let lastMNode = head;

while (currentNode !== null) {
let mCount = m, nCount = n;

while (currentNode !== null && mCount > 0) {
lastMNode = currentNode;
currentNode = currentNode.next;
mCount--;
}

while (currentNode !== null && nCount > 0) {
currentNode = currentNode.next;
nCount--;
}

lastMNode.next = currentNode;
}
return head;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2160 650
Задача: 1196. How Many Apples Can You Put into the Basket
Сложность: easy

У вас есть несколько яблок и корзина, которая может выдержать до 5000 единиц веса.

Дан целочисленный массив weight, где weight[i] — это вес i-го яблока. Верните максимальное количество яблок, которые можно положить в корзину.

Пример:
Input: weight = [100,200,150,1000]
Output: 4
Explanation: All 4 apples can be carried by the basket since their sum of weights is 1450.


👨‍💻 Алгоритм:

1⃣Преобразование массива в мин-кучу:
Преобразуйте массив weight в мин-кучу, чтобы получить минимальные элементы первым.

2⃣Инициализация переменных:
Инициализируйте переменные apples для подсчета количества яблок и units для записи текущего веса корзины.

3⃣Добавление яблок в корзину:
Пока текущий вес корзины меньше 5000 единиц и в куче остаются элементы:
Увеличивайте apples на 1.
Увеличивайте units на значение, извлеченное из кучи.

😎 Решение:
class Solution {
maxNumberOfApples(weight) {
weight.sort((a, b) => a - b);
let apples = 0, units = 0;

for (const w of weight) {
if (units + w <= 5000) {
units += w;
apples++;
} else {
break;
}
}
return apples;
}
}


Ставь 👍 и забирай 📚 Базу знаний
  • 👍 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →