TGViewer
Channel Public Channel
JavaScript | LeetCode

JavaScript | LeetCode

@easy_frontend_task

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

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

Showing posts older than #2435 · Back to latest

Older Posts 20 shown
Post #2433 579
Задача: 1062. Longest Repeating Substring
Сложность: medium

Дана строка s. Вернуть длину самой длинной повторяющейся подстроки. Если повторяющаяся подстрока отсутствует, вернуть 0.

Пример:
Input: s = "abcd"
Output: 0
Explanation: There is no repeating substring.


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

1⃣Перемещайте скользящее окно длиной L по строке длиной N.

2⃣Проверьте, находится ли строка в скользящем окне в хэш-наборе уже виденных строк. Если да, то повторяющаяся подстрока находится здесь. Если нет, сохраните строку из скользящего окна в хэш-наборе.

3⃣Очевидный недостаток этого подхода — большое потребление памяти в случае длинных строк.

😎 Решение:
class Solution {
search(L, n, S) {
const seen = new Set();
for (let start = 0; start <= n - L; ++start) {
const tmp = S.substring(start, start + L);
if (seen.has(tmp)) return start;
seen.add(tmp);
}
return -1;
}

longestRepeatingSubstring(S) {
const n = S.length;
let left = 1, right = n;
while (left <= right) {
const L = left + Math.floor((right - left) / 2);
if (this.search(L, n, S) !== -1) {
left = L + 1;
} else {
right = L - 1;
}
}
return left - 1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2431 501
Задача: 1370. Increasing Decreasing String
Сложность: easy

Дана строка s. Переставьте символы строки, используя следующий алгоритм:

Выберите наименьший символ из s и добавьте его к результату.
Выберите наименьший символ из s, который больше последнего добавленного символа, и добавьте его.
Повторяйте шаг 2, пока не сможете выбрать больше символов.
Выберите наибольший символ из s и добавьте его к результату.
Выберите наибольший символ из s, который меньше последнего добавленного символа, и добавьте его.
Повторяйте шаг 5, пока не сможете выбрать больше символов.
Повторяйте шаги с 1 по 6, пока не выберете все символы из s.
На каждом этапе, если наименьший или наибольший символ появляется более одного раза, вы можете выбрать любое его вхождение и добавить его к результату.

Верните результирующую строку после сортировки s с помощью этого алгоритма.

Пример:
Input: s = "rat"
Output: "art"
Explanation: The word "rat" becomes "art" after re-ordering it with the mentioned algorithm.


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

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

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

3⃣Проверка завершения:
Повторяйте шаги 2 и 3, пока не будут добавлены все символы из строки s в result.

😎 Решение:
var sortString = function(s) {
const charCount = new Array(26).fill(0);
for (const c of s) {
charCount[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
}

let result = '';
while (result.length < s.length) {
for (let c = 0; c < 26; c++) {
if (charCount[c] > 0) {
result += String.fromCharCode(c + 'a'.charCodeAt(0));
charCount[c]--;
}
}
for (let c = 25; c >= 0; c--) {
if (charCount[c] > 0) {
result += String.fromCharCode(c + 'a'.charCodeAt(0));
charCount[c]--;
}
}
}

return result;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2421 459
Задача: 1036. Escape a Large Maze
Сложность: hard

Имеется сетка размером 1 миллион на 1 миллион на плоскости XY, координаты каждого квадрата сетки - (x, y). Мы начинаем с исходного квадрата = [sx, sy] и хотим достичь цели = [tx, ty]. Существует также массив заблокированных квадратов, где каждый заблокированный[i] = [xi, yi] представляет собой заблокированный квадрат с координатами (xi, yi). Каждый ход мы можем пройти один квадрат на север, восток, юг или запад, если квадрат не находится в массиве заблокированных квадратов. Нам также не разрешается выходить за пределы сетки. Возвращается true тогда и только тогда, когда можно достичь целевого квадрата из исходного квадрата с помощью последовательности правильных ходов.

Пример:
Input: blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
Output: false


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

1⃣Обработка входных данных:
Загрузите координаты исходного квадрата sx, sy, целевого квадрата tx, ty и список заблокированных квадратов blocked.

2⃣Проверка простого случая:
Если список blocked пуст, верните true, так как путь не будет заблокирован.
Проверка начальной или целевой клетки:
Если исходная или целевая клетка заблокированы, верните false.

3⃣Поиск пути с использованием BFS или DFS:
Используйте алгоритм поиска в ширину (BFS) или поиска в глубину (DFS) для поиска пути от sx, sy до tx, ty, избегая заблокированных клеток.
Если обнаружен путь, верните true, в противном случае верните false.

😎 Решение:
var isEscapePossible = function(blocked, source, target) {
const blockedSet = new Set(blocked.map(b => `${b[0]},${b[1]}`));
const src = `${source[0]},${source[1]}`;
const tgt = `${target[0]},${target[1]}`;

if (blockedSet.has(src) || blockedSet.has(tgt)) return false;

const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]];
const maxArea = blocked.length * (blocked.length - 1) / 2;

const bfs = (start, end) => {
const queue = [start];
const visited = new Set([start]);

while (queue.length) {
if (visited.size > maxArea) return true;
const [x, y] = queue.shift().split(',').map(Number);
for (const [dx, dy] of directions) {
const nx = x + dx, ny = y + dy;
const next = `${nx},${ny}`;
if (nx >= 0 && nx < 1_000_000 && ny >= 0 && ny < 1_000_000 && !visited.has(next) && !blockedSet.has(next)) {
if (next === end) return true;
queue.push(next);
visited.add(next);
}
}
}
return false;
};

return bfs(src, tgt) && bfs(tgt, src);
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2419 488
Задача: №27. Remove Element
Сложность: easy

Дан массив nums и число val.
Нужно удалить все вхождения val из массива, на месте, и вернуть количество оставшихся элементов.
Элементы можно переставлять. Остаток массива не важен.

Пример:
Input: nums = [3,2,2,3], val = 3  
Output: 2


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

1️⃣ Вводим указатель k = 0, который отслеживает количество элементов, не равных val.

2️⃣ Проходим по каждому элементу x в массиве:
- Если x !== val, присваиваем nums[k] = x и увеличиваем k

3️⃣ После прохода k будет равен количеству нужных элементов. Возвращаем k.

😎 Решение:
var removeElement = function (nums, val) {
let k = 0;
for (const x of nums) {
if (x !== val) {
nums[k++] = x;
}
}
return k;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2417 470
Задача: 1326. Minimum Number of Taps to Open to Water a Garden
Сложность: hard

Есть одномерный сад на оси x. Сад начинается в точке 0 и заканчивается в точке n. (т.е. длина сада равна n).

В саду есть n + 1 кранов, расположенных в точках [0, 1, ..., n].

Даны целое число n и целочисленный массив ranges длиной n + 1, где ranges[i] (индексация начинается с 0) означает, что i-й кран может поливать область [i - ranges[i], i + ranges[i]], если он открыт.

Верните минимальное количество кранов, которые должны быть открыты для полива всего сада. Если сад невозможно полить, верните -1.

Пример:
Input: n = 5, ranges = [3,4,1,1,0,0]
Output: 1
Explanation: The tap at point 0 can cover the interval [-3,3]
The tap at point 1 can cover the interval [-3,5]
The tap at point 2 can cover the interval [1,3]
The tap at point 3 can cover the interval [2,4]
The tap at point 4 can cover the interval [4,4]
The tap at point 5 can cover the interval [5,5]
Opening Only the second tap will water the whole garden [0,5]


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

1⃣Объявите массив dp размера n+1. Инициализируйте его значениями бесконечности (в коде используем большое число 10^9 для представления бесконечности). Установите dp[0] в 0 (базовый случай DP).

2⃣Итерируйтесь от i до n (через каждый кран слева направо). Рассчитайте самую левую позицию, достижимую текущим краном, как tap_start=max(0,i−ranges[i]). И самую правую позицию tap_end=min(n,i+ranges[i]).

3⃣Итерируйтесь через позиции j от tap_start до tap_end (в пределах досягаемости крана). Обновите dp[tap_end] значением dp[j]+1, если оно меньше. Если dp[n] остается бесконечным, значит, полить весь сад невозможно, и мы возвращаем −1. Верните dp[n].

😎 Решение:
var minTaps = function(n, ranges) {
const INF = Number.MAX_SAFE_INTEGER;
const dp = new Array(n + 1).fill(INF);
dp[0] = 0;

for (let i = 0; i <= n; i++) {
const tapStart = Math.max(0, i - ranges[i]);
const tapEnd = Math.min(n, i + ranges[i]);

for (let j = tapStart; j <= tapEnd; j++) {
dp[tapEnd] = Math.min(dp[tapEnd], dp[j] + 1);
}
}

return dp[n] === INF ? -1 : dp[n];
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2415 435
Задача: 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 #2413 424
Задача: 247. Strobogrammatic Number II
Сложность: medium

Дано целое число n, верните все стробограмматические числа длины n. Ответ можно возвращать в любом порядке.
Стробограмматическое число — это число, которое выглядит одинаково при повороте на 180 градусов (если посмотреть вверх ногами).

Пример:
Input: n = 2
Output: ["11","69","88","96"]


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

1️⃣Инициализируйте структуру данных reversiblePairs, которая содержит все пары обратимых цифр. Вызовите и верните результат рекурсивной функции generateStroboNumbers(n, finalLength), где первый аргумент указывает, что текущий вызов создаст все стробограмматические числа длиной n, а второй аргумент указывает длину конечных стробограмматических чисел, которые мы будем генерировать, и будет использоваться для проверки возможности добавления '0' в начало и конец числа.

2️⃣Создайте функцию generateStroboNumbers(n, finalLength), которая вернет все стробограмматические числа длиной n:
Проверьте базовые случаи: если n == 0, верните массив с пустой строкой [""]; если n == 1, верните ["0", "1", "8"].
Вызовите generateStroboNumbers(n - 2, finalLength), чтобы получить все стробограмматические числа длиной (n-2), и сохраните их в subAns.
Инициализируйте пустой массив currStroboNums для хранения стробограмматических чисел длиной n.

3️⃣Для каждого числа в subAns добавьте все reversiblePairs в начало и конец, за исключением случая, когда текущая пара '00' и n == finalLength (потому что нельзя добавить '0' в начало числа), и добавьте это новое число в currStroboNums. В конце функции верните все стробограмматические числа, т.е. currStroboNums.

😎 Решение:
class Solution {
constructor() {
this.reversiblePairs = [
['0', '0'], ['1', '1'],
['6', '9'], ['8', '8'], ['9', '6']
];
}

generateStroboNumbers(n, finalLength) {
if (n === 0) {
return [""];
}

if (n === 1) {
return ["0", "1", "8"];
}

const prevStroboNums = this.generateStroboNumbers(n - 2, finalLength);
const currStroboNums = [];

for (const prevStroboNum of prevStroboNums) {
for (const pair of this.reversiblePairs) {
if (pair[0] !== '0' || n !== finalLength) {
currStroboNums.push(pair[0] + prevStroboNum + pair[1]);
}
}
}

return currStroboNums;
}

findStrobogrammatic(n) {
return this.generateStroboNumbers(n, n);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2411 492
Задача: 322. Coin Change
Сложность: medium

Дан целочисленный массив coins, представляющий монеты разных номиналов, и целое число amount, представляющее общую сумму денег.
Верните минимальное количество монет, необходимых для составления этой суммы. Если эту сумму невозможно составить с помощью комбинации монет, верните -1.
Вы можете предположить, что у вас есть неограниченное количество монет каждого типа.

Пример:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1


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

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

2⃣Функция backtracking
Внутри функции backtracking для каждой монеты из массива coins:
Проверьте все возможные количества монет данного номинала (от 0 до максимального количества, которое можно использовать без превышения amount). Для каждой комбинации монет обновите сумму и вызовите функцию рекурсивно для проверки оставшейся суммы. Если текущая комбинация дает меньшую сумму монет, обновите минимальное количество монет.

3⃣Возврат результата
Если комбинация, дающая сумму amount, найдена, верните минимальное количество монет, иначе верните -1.

😎 Решение:
var coinChange = function(coins, amount) {
return coinChangeHelper(0, coins, amount);
};

var coinChangeHelper = function(idxCoin, coins, amount) {
if (amount === 0) return 0;
if (idxCoin < coins.length && amount > 0) {
let maxVal = Math.floor(amount / coins[idxCoin]);
let minCost = Number.MAX_SAFE_INTEGER;
for (let x = 0; x <= maxVal; x++) {
if (amount >= x * coins[idxCoin]) {
let res = coinChangeHelper(idxCoin + 1, coins, amount - x * coins[idxCoin]);
if (res !== -1) {
minCost = Math.min(minCost, res + x);
}
}
}
return minCost === Number.MAX_SAFE_INTEGER ? -1 : minCost;
}
return -1;
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2410 510
Задача: 1044. Longest Duplicate Substring
Сложность: hard

Учитывая строку s, рассмотрите все дублированные подстроки: (смежные) подстроки s, которые встречаются 2 или более раз.Вхождения могут перекрываться. Верните любую дублированную подстроку, которая имеет наибольшую возможную длину.Если в s нет дублирующейся подстроки, ответом будет "".

Пример:
Input: s = "banana"
Output: "ana"


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

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

2⃣Использование хеширования для проверки наличия дублированной подстроки определенной длины:
Для каждой длины, определенной двоичным поиском, используем хеширование для поиска подстрок.

3⃣Хеширование с помощью функции rolling hash:
Rolling hash позволяет быстро вычислять хеши подстрок фиксированной длины и сравнивать их для поиска дубликатов.

😎 Решение:
function longestDupSubstring(s) {
function search(len) {
let seen = new Set();
for (let i = 0; i <= s.length - len; i++) {
let sub = s.slice(i, i + len);
if (seen.has(sub)) {
return sub;
}
seen.add(sub);
}
return "";
}

let left = 1, right = s.length;
let result = "";
while (left < right) {
let mid = Math.floor((left + right) / 2);
let dup = search(mid);
if (dup) {
result = dup;
left = mid + 1;
} else {
right = mid;
}
}
return result;
}


Ставь 👍 и забирай 📚 Базу знаний
  • 👍 1
Post #2408 521
Задача: 920. Number of Music Playlists
Сложность: hard

В вашем плеере есть n разных песен. Во время путешествия вы хотите прослушать goal песен (не обязательно разных). Чтобы избежать скуки, вы создадите плейлист таким образом, чтобы: каждая песня играла хотя бы один раз. Песня может быть проиграна снова только в том случае, если было проиграно k других песен. Учитывая n, цель и k, верните количество возможных плейлистов, которые вы можете создать. Поскольку ответ может быть очень большим, верните его по модулю 10^9 + 7.

Пример:
Input: n = 3, goal = 3, k = 1
Output: 6


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

1⃣Создать двумерный массив dp, где dp[i][j] представляет количество возможных плейлистов длины i, содержащих j различных песен.

2⃣Инициализировать dp[0][0] = 1, что означает, что существует один способ создать плейлист длины 0 с 0 песнями.
Заполнить массив dp, используя два случая:
Добавление новой песни, которая не была проиграна раньше: dp[i][j] += dp[i-1][j-1] * (n - j + 1)
Повторное проигрывание песни, если было проиграно k других песен: dp[i][j] += dp[i-1][j] * max(j - k, 0)

3⃣Ответ находится в dp[goal][n].

😎 Решение:
var numMusicPlaylists = function(n, goal, k) {
const MOD = 10**9 + 7;
let dp = Array.from({ length: goal + 1 }, () => Array(n + 1).fill(0));
dp[0][0] = 1;

for (let i = 1; i <= goal; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] = dp[i-1][j-1] * (n - j + 1) % MOD;
if (j > k) {
dp[i][j] = (dp[i][j] + dp[i-1][j] * (j - k) % MOD) % MOD;
}
}
}

return dp[goal][n];
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2405 460
Задача: 422. Valid Word Square
Сложность: easy

Дан массив строк words, верните true, если он образует правильный квадрат слов.

Последовательность строк образует правильный квадрат слов, если k-я строка и k-й столбец читаются одинаково, где 0 <= k < max(numRows, numColumns).

Пример:
Input: words = ["abcd","bnrt","crmy","dtye"]
Output: true
Explanation:
The 1st row and 1st column both read "abcd".
The 2nd row and 2nd column both read "bnrt".
The 3rd row and 3rd column both read "crmy".
The 4th row and 4th column both read "dtye".
Therefore, it is a valid word square.


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

1⃣Инициализируйте переменные: cols для максимальной длины слов в массиве, rows для количества строк в массиве words, и пустой массив newWords для хранения новых слов, представленных каждым столбцом.

2⃣Итерация по массиву words, определение максимальной длины слова для cols, проверка, что количество строк равно количеству столбцов. Если условие не выполняется, возвращаем false.

3⃣Для каждого столбца col от 0 до cols - 1, формируем строку newWord из символов на позиции (row, col) для каждой строки. Сохраняем newWord в массиве newWords. В конце, если newWords и words равны, возвращаем true, иначе false.

😎 Решение:
class Solution {
validWordSquare(words) {
let cols = 0;
const rows = words.length;
const newWords = [];

for (const word of words) {
cols = Math.max(cols, word.length);
}

if (cols !== words[0].length || rows !== cols) {
return false;
}

for (let col = 0; col < cols; ++col) {
let newWord = "";
for (let row = 0; row < rows; ++row) {
if (col < words[row].length) {
newWord += words[row][col];
}
}
newWords.push(newWord);
}

return words.join(",") === newWords.join(",");
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2395 485
Задача: 1420. Build Array Where You Can Find The Maximum Exactly K Comparisons
Сложность: hard

Вам даны три целых числа n, m и k. Рассмотрим следующий алгоритм для нахождения максимального элемента в массиве положительных целых чисел:
maximum_value = -1
maximum_index = -1
search_cost = 0
n = arr.length
for (i = 0; i < n; i++){
if (maximum_value < arr[i]){
maximum_value = arr[i]
maximum_index = i
search_cost = search_cost + 1
}
}
return maximum_index

Вам необходимо построить массив arr, который имеет следующие свойства:
arr содержит ровно n целых чисел.
1 <= arr[i] <= m, где (0 <= i < n).
После применения указанного алгоритма к arr, значение search_cost равно k.
Верните количество способов построить массив arr с учетом указанных условий. Так как ответ может быть очень большим, ответ должен быть вычислен по модулю 10^9 + 7.

Пример:
Input: n = 2, m = 3, k = 1
Output: 6
Explanation: The possible arrays are [1, 1], [2, 1], [2, 2], [3, 1], [3, 2] [3, 3]


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

1⃣Инициализация и базовые случаи: Инициализируем 3D массив dp размером [n+1][m+1][k+1]. Устанавливаем базовые случаи: dp[n][...][0] = 1.

2⃣Итерация и обновление массива dp: Проходим в обратном порядке по индексам i от n-1 до 0, по maxSoFar от m до 0 и по remain от 0 до k. Для каждого из этих значений обновляем dp массив, используя предыдущие результаты для вычисления текущих значений.

3⃣Возврат результата: Возвращаем значение dp[0][0][k], которое является решением исходной задачи.

😎 Решение:
var numOfArrays = function(n, m, k) {
const MOD = 1_000_000_007;
const dp = Array.from({ length: n + 1 }, () => Array.from({ length: m + 1 }, () => Array(k + 1).fill(0)));

for (let num = 0; num <= m; num++) {
dp[n][num][0] = 1;
}

for (let i = n - 1; i >= 0; i--) {
for (let maxSoFar = m; maxSoFar >= 0; maxSoFar--) {
for (let remain = 0; remain <= k; remain++) {
let ans = 0;
for (let num = 1; num <= maxSoFar; num++) {
ans = (ans + dp[i + 1][maxSoFar][remain]) % MOD;
}

if (remain > 0) {
for (let num = maxSoFar + 1; num <= m; num++) {
ans = (ans + dp[i + 1][num][remain - 1]) % MOD;
}
}

dp[i][maxSoFar][remain] = ans;
}
}
}

return dp[0][0][k];
};


Ставь 👍 и забирай 📚 Базу знаний
Post #2393 509
Задача: 412. Fizz Buzz
Сложность: easy

Учитывая целое число n, верните строковый массив answer (с индексом 1), где: answer[i] == "FizzBuzz", если i делится на 3 и 5. answer[i] == "Fizz", если i делится на 3. answer[i] == "Buzz", если i делится на 5. answer[i] == i (как строка), если ни одно из перечисленных условий не верно.

Пример:
Input: nums = [1,2,2]
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]


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

1⃣Создайте пустой список для хранения результата.

2⃣Пройдите по всем числам от 1 до n и для каждого числа выполните проверку: Если число делится на 3 и на 5, добавьте "FizzBuzz". Если число делится на 3, добавьте "Fizz". Если число делится на 5, добавьте "Buzz". Если ни одно из условий не выполнено, добавьте само число как строку.

3⃣Верните полученный список.

😎 Решение:
function fizzBuzz(n) {
const answer = [];
for (let i = 1; i <= n; i++) {
if (i % 3 === 0 && i % 5 === 0) {
answer.push("FizzBuzz");
} else if (i % 3 === 0) {
answer.push("Fizz");
} else if (i % 5 === 0) {
answer.push("Buzz");
} else {
answer.push(i.toString());
}
}
return answer;
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2391 536
Задача: 674. Longest Continuous Increasing Subsequence
Сложность: easy

Дан неотсортированный массив целых чисел nums, верните длину самой длинной непрерывной возрастающей подпоследовательности (т.е. подмассива). Подпоследовательность должна быть строго возрастающей.
Непрерывная возрастающая подпоследовательность определяется двумя индексами l и r (l < r) так, что она имеет вид [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]] и для каждого l <= i < r выполняется nums[i] < nums[i + 1].

Пример:
Input: nums = [1,3,5,4,7]
Output: 3
Explanation: The longest continuous increasing subsequence is [1,3,5] with length 3.
Even though [1,3,5,7] is an increasing subsequence, it is not continuous as elements 5 and 7 are separated by element
4.


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

1⃣Каждая (непрерывная) возрастающая подпоследовательность не пересекается, и граница каждой такой подпоследовательности возникает, когда nums[i-1] >= nums[i]. В этом случае начинается новая возрастающая подпоследовательность с nums[i], и мы сохраняем такой i в переменной anchor.

2⃣Например, если nums = [7, 8, 9, 1, 2, 3], то anchor начинается с 0 (nums[anchor] = 7) и затем устанавливается на anchor = 3 (nums[anchor] = 1). Независимо от значения anchor, мы записываем кандидата на ответ длиной i - anchor + 1, длина подмассива nums[anchor], nums[anchor+1], ..., nums[i], и наш ответ обновляется соответствующим образом.

3⃣Возвращаем максимальную длину найденной непрерывной возрастающей подпоследовательности.

😎 Решение:
var findLengthOfLCIS = function(nums) {
let ans = 0, anchor = 0;
for (let i = 0; i < nums.length; ++i) {
if (i > 0 && nums[i - 1] >= nums[i]) {
anchor = i;
}
ans = Math.max(ans, i - anchor + 1);
}
return ans;
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2389 477
Задача: 1295. Find Numbers with Even Number of Digits
Сложность: easy

Дан массив чисел nums. Верните количество чисел в массиве, которые содержат четное количество цифр.

Пример:
Input: nums = [12,345,2,6,7896]
Output: 2
Explanation:
12 contains 2 digits (even number of digits).
345 contains 3 digits (odd number of digits).
2 contains 1 digit (odd number of digits).
6 contains 1 digit (odd number of digits).
7896 contains 4 digits (even number of digits).
Therefore only 12 and 7896 contain an even number of digits.


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

1⃣Определите вспомогательную функцию hasEvenDigits, которая принимает num в качестве входных данных и возвращает true, если количество цифр четное, иначе возвращает false.

2⃣Внутри функции hasEvenDigits. Инициализируйте переменную digitCount значением 0. Пока num не равно нулю: Увеличивайте digitCount на 1. Делите num на 10. Возвращайте digitCount & 1 == 0.

3⃣В функции findNumbers. Инициализируйте переменную evenDigitCount значением 0. Для каждого числа num в массиве nums, проверяйте, возвращает ли hasEvenDigits(num) значение true. Если да, увеличивайте evenDigitCount на 1. Возвращайте evenDigitCount.

😎 Решение:
class Solution {
hasEvenDigits(num) {
let digitCount = 0
while (num > 0) {
digitCount++
num = Math.floor(num / 10)
}
return (digitCount & 1) === 0
}

findNumbers(nums) {
let evenDigitCount = 0
for (let num of nums) {
if (this.hasEvenDigits(num)) {
evenDigitCount++
}
}
return evenDigitCount
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2387 452
Задача: 1125. Smallest Sufficient Team
Сложность: hard

В проекте у вас есть список необходимых навыков req_skills и список людей. i-й человек people[i] содержит список навыков, которыми обладает этот человек.

Рассмотрим достаточную команду: набор людей, такой что для каждого необходимого навыка из req_skills, есть по крайней мере один человек в команде, который обладает этим навыком. Мы можем представить эти команды индексами каждого человека.

Например, команда = [0, 1, 3] представляет людей с навыками people[0], people[1] и people[3].
Верните любую достаточную команду наименьшего возможного размера, представленную индексами каждого человека. Вы можете вернуть ответ в любом порядке.

Гарантируется, что ответ существует.

Пример:
Input: req_skills = ["algorithms","math","java","reactjs","csharp","aws"],
people = [["algorithms","math","java"],["algorithms","math","reactjs"],
["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]]
Output: [1,2]


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

1⃣Инициализация и создание масок навыков:
Определите количество людей n и количество необходимых навыков m.
Создайте хэш-таблицу skillId, чтобы сопоставить каждому навыку уникальный индекс.
Создайте массив skillsMaskOfPerson, который будет содержать битовые маски навыков для каждого человека.

2⃣Динамическое программирование (DP):
Создайте массив dp размера 2^m и заполните его значениями (1 << n) - 1.
Установите dp[0] в 0 (базовый случай).
Для каждого skillsMask от 1 до 2^m - 1:
- для каждого человека i:
- вычислите smallerSkillsMask как skillsMask & ~skillsMaskOfPerson[i].
- если smallerSkillsMask отличается от skillsMask, обновите dp[skillsMask], если новая команда лучше (имеет меньше установленных битов).

3⃣Формирование ответа:
Извлеките ответ из dp и верните массив индексов людей, составляющих минимальную достаточную команду.

😎 Решение:
var smallestSufficientTeam = function(req_skills, people) {
const n = people.length, m = req_skills.length;
const skillId = new Map(req_skills.map((skill, i) => [skill, i]));
const skillsMaskOfPerson = Array(n).fill(0);
for (let i = 0; i < n; i++) {
for (const skill of people[i]) {
if (skillId.has(skill)) {
skillsMaskOfPerson[i] |= 1 << skillId.get(skill);
}
}
}
const dp = Array(1 << m).fill((1 << n) - 1);
dp[0] = 0;
for (let skillsMask = 1; skillsMask < (1 << m); skillsMask++) {
for (let i = 0; i < n; i++) {
const smallerSkillsMask = skillsMask & ~skillsMaskOfPerson[i];
if (smallerSkillsMask !== skillsMask) {
const peopleMask = dp[smallerSkillsMask] | (1 << i);
if (bitCount(peopleMask) < bitCount(dp[skillsMask])) {
dp[skillsMask] = peopleMask;
}
}
}
}
const answerMask = dp[(1 << m) - 1];
const result = [];
for (let i = 0; i < n; i++) {
if ((answerMask >> i) & 1) {
result.push(i);
}
}
return result;
};

function bitCount(n) {
let count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
return count;
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2385 516
Задача: 846. Hand of Straights
Сложность: medium

У Алисы есть некоторое количество карт, и она хочет переставить карты в группы так, чтобы каждая группа была размером groupSize и состояла из groupSize последовательных карт.

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

Пример:
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]


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

1⃣Проверьте, делится ли длина массива hand на groupSize. Если нет, верните false.

2⃣Создайте карту cardCount для хранения количества каждой карты в массиве hand.

3⃣Итерируйте по массиву hand и обновляйте карту cardCount. Затем итерируйте снова для создания групп:
Найдите начальную карту startCard для потенциальной последовательности, уменьшая startCard, пока не найдёте карту, которая отсутствует в карте cardCount.
Попробуйте сформировать последовательность из groupSize карт, начиная с startCard. Если какая-либо карта в потенциальной последовательности отсутствует в карте cardCount, верните false.
Если последовательность можно сформировать, уменьшите количество каждой карты в последовательности в карте cardCount.

😎 Решение:
var isNStraightHand = function(hand, groupSize) {
if (hand.length % groupSize !== 0) {
return false;
}

const cardCount = new Map();
for (let card of hand) {
cardCount.set(card, (cardCount.get(card) || 0) + 1);
}

hand.sort((a, b) => a - b);

for (let card of hand) {
if (cardCount.get(card) === 0) {
continue;
}

for (let nextCard = card; nextCard < card + groupSize; nextCard++) {
if ((cardCount.get(nextCard) || 0) === 0) {
return false;
}
cardCount.set(nextCard, cardCount.get(nextCard) - 1);
}
}

return true;
};


Ставь 👍 и забирай 📚 Базу знаний
  • 🔥 1
Post #2383 590
Задача: 288. Unique Word Abbreviation
Сложность: medium

Сокращение слова — это объединение его первой буквы, количества символов между первой и последней буквой и последней буквы. Если слово состоит только из двух символов, то оно является сокращением само по себе.
Например:
dog --> d1g, потому что между первой буквой 'd' и последней буквой 'g' одна буква.
internationalization --> i18n, потому что между первой буквой 'i' и последней буквой 'n' 18 букв.
it --> it, потому что любое слово из двух символов является своим собственным сокращением.
Реализуйте класс ValidWordAbbr:
ValidWordAbbr(String[] dictionary) Инициализирует объект со словарем слов.
boolean isUnique(string word) Возвращает true, если выполняется одно из следующих условий (в противном случае возвращает false):
В словаре нет слова, сокращение которого равно сокращению слова word.
Для любого слова в словаре, сокращение которого равно сокращению слова word, это слово и word одинаковы.

Пример:
Input
["ValidWordAbbr", "isUnique", "isUnique", "isUnique", "isUnique", "isUnique"]
[[["deer", "door", "cake", "card"]], ["dear"], ["cart"], ["cane"], ["make"], ["cake"]]
Output
[null, false, true, false, true, true]

Explanation
ValidWordAbbr validWordAbbr = new ValidWordAbbr(["deer", "door", "cake", "card"]);
validWordAbbr.isUnique("dear"); // return false, dictionary word "deer" and word "dear" have the same abbreviation "d2r" but are not the same.
validWordAbbr.isUnique("cart"); // return true, no words in the dictionary have the abbreviation "c2t".
validWordAbbr.isUnique("cane"); // return false, dictionary word "cake" and word "cane" have the same abbreviation "c2e" but are not the same.
validWordAbbr.isUnique("make"); // return true, no words in the dictionary have the abbreviation "m2e".
validWordAbbr.isUnique("cake"); // return true, because "cake" is already in the dictionary and no other word in the dictionary has "c2e" abbreviation.


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

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

2⃣Генерация сокращений:
При инициализации объекта ValidWordAbbr пройдите через каждое слово в словаре и создайте его сокращение.
Если сокращение уже существует в abbrDict, установите значение в false (не уникальное). В противном случае установите значение в true (уникальное).

3⃣Проверка уникальности:
Для метода isUnique создайте сокращение для входного слова и проверьте, есть ли это сокращение в abbrDict.
Если сокращение отсутствует в abbrDict, возвращайте true.
Если сокращение присутствует и оно уникально, проверьте, есть ли это слово в словаре. Если да, возвращайте true, в противном случае - false.

😎 Решение:
class ValidWordAbbr {
constructor(dictionary) {
this.abbrDict = new Map();
this.dict = new Set(dictionary);
for (const word of this.dict) {
const abbr = this.toAbbr(word);
this.abbrDict.set(abbr, !this.abbrDict.get(abbr));
}
}

isUnique(word) {
const abbr = this.toAbbr(word);
const hasAbbr = this.abbrDict.get(abbr);
return hasAbbr === undefined || (hasAbbr && this.dict.has(word));
}

toAbbr(word) {
const n = word.length;
if (n <= 2) {
return word;
}
return `${word[0]}${n - 2}${word[n - 1]}`;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2381 573
Задача: 209. Minimum Size Subarray Sum
Сложность: medium

Дан массив положительных целых чисел nums и положительное целое число target. Верните минимальную длину подмассива, сумма которого больше или равна target. Если такого подмассива нет, верните 0.

Пример:
Input: target = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: The subarray [4,3] has the minimal length under the problem constraint.


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

1️⃣Инициализация переменных:
Создайте три целочисленные переменные left, right и sumOfCurrentWindow. Переменные left и right формируют подмассив, указывая на начальные и конечные индексы текущего подмассива (или окна), а sumOfCurrentWindow хранит сумму этого окна. Инициализируйте все их значением 0.
Создайте еще одну переменную res для хранения ответа на задачу. Инициализируйте ее большим целым значением.

2️⃣Итерация по массиву:
Итерируйте по массиву nums с помощью right, начиная с right = 0 до nums.length - 1, увеличивая right на 1 после каждой итерации. Выполняйте следующее внутри этой итерации:
Добавьте элемент с индексом right к текущему окну, увеличив sumOfCurrentWindow на nums[right].
Проверьте, если sumOfCurrentWindow >= target. Если да, у нас есть подмассив, который удовлетворяет условию. В результате, попытайтесь обновить переменную ответа res длиной этого подмассива. Выполните res = min(res, right - left + 1). Затем удалите первый элемент из этого окна, уменьшив sumOfCurrentWindow на nums[left] и увеличив left на 1. Этот шаг повторяется во внутреннем цикле, пока sumOfCurrentWindow >= target.

3️⃣Возврат результата:
Текущая сумма окна теперь меньше target. Нужно добавить больше элементов в окно. В результате, увеличивается right на 1.
Верните res.

😎 Решение:
class Solution {
minSubArrayLen(target, nums) {
let left = 0, sumOfCurrentWindow = 0;
let res = Number.MAX_VALUE;

for (let right = 0; right < nums.length; right++) {
sumOfCurrentWindow += nums[right];

while (sumOfCurrentWindow >= target) {
res = Math.min(res, right - left + 1);
sumOfCurrentWindow -= nums[left];
left++;
}
}

return res === Number.MAX_VALUE ? 0 : res;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #2378 587
Задача: 638. Shopping Offers
Сложность: medium

В магазине LeetCode Store есть n предметов для продажи. Каждый товар имеет свою цену. Однако существуют специальные предложения, и специальное предложение состоит из одного или нескольких различных видов товаров с распродажной ценой. Вам дан целочисленный массив price, где price[i] - цена i-го товара, и целочисленный массив needs, где needs[i] - количество штук i-го товара, который вы хотите купить. Вам также дан массив special, где special[i] имеет размер n + 1, где special[i][j] - количество штук j-го товара в i-м предложении, а special[i][n] (т.е., Возвращает наименьшую цену, которую вы можете заплатить за определенный товар из заданных, где вы могли бы оптимально использовать специальные предложения. Вам не разрешается покупать больше товаров, чем вы хотите, даже если это снизит общую цену. Вы можете использовать любое из специальных предложений столько раз, сколько захотите.

Пример:
Input: price = [2,5], special = [[3,0,5],[1,2,10]], needs = [3,2]
Output: 14


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

1⃣Рекурсивное вычисление стоимости
Определите функцию, которая рекурсивно вычисляет минимальную стоимость для оставшихся нужд, используя динамическое программирование для запоминания уже вычисленных значений.

2⃣Использование специальных предложений
Для каждой комбинации товаров в специальных предложениях, определите, можно ли использовать это предложение без превышения нужд. Если можно, вычислите новую стоимость, учитывая это предложение.

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

😎 Решение:
var shoppingOffers = function(price, special, needs) {
const memo = new Map();

const dfs = (needs) => {
const key = needs.join(',');
if (memo.has(key)) {
return memo.get(key);
}

let minPrice = needs.reduce((sum, need, i) => sum + need * price[i], 0);

for (let offer of special) {
const newNeeds = needs.map((need, i) => need - offer[i]);
if (newNeeds.every(need => need >= 0)) {
minPrice = Math.min(minPrice, offer[offer.length - 1] + dfs(newNeeds));
}
}

memo.set(key, minPrice);
return minPrice;
};

return dfs(needs);
};


Ставь 👍 и забирай 📚 Базу знаний
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 →