Задача: №20. Valid Parentheses #easy
Условие:
Решение:
Пояснение:
Пройдите по строке скобок s. При
обнаружении левой скобки вставьте
текущую левую скобку в стек; при
обнаружении правой скобки извлеките верхний
элемент из стека (если стек пуст,
сразу верните значение false ) и оцените
, соответствует ли оно. Если оно не совпадает, напрямую
верните значение false.
В качестве альтернативы, при обнаружении левой
скобки вы можете поместить соответствующую
правую скобку в стек; при
обнаружении правой скобки извлеките верхний
элемент стека (если стек пуст,
непосредственно верните значение false ) и оцените, равны ли
они. Если они не совпадают,
напрямую верните значение false.
Разница между этими двумя
методами заключается только во времени
преобразования скобок: один - при вставке в стек
, а другой - при
извлечении из стека.
В конце обхода, если стек
пуст, это означает, что строка в скобках верна,
возвращает значение true; в противном случае возвращает значение false.
Временная сложность равна O(n), а
пространственная сложность равна O(n). Здесь n - это
длина строки скобок s.
Условие:
Учитывая строку s, содержащую только символы '(', ')', '{', '}', '[' и ']', определите, является ли входная строка допустимой. Входная строка действительна, если: Открытые скобки должны закрываться скобками того же типа.
Открытые скобки должны закрываться в правильном порядке.
Каждой закрывающей скобке соответствует открытая скобка того же типа.
Решение:
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
let stk = [];
for (const c of s) {
if (c == '(' c == '{' c == '[') {
stk.push(c);
} else if (stk.length == 0 !match(stk[stk.length - 1], c)) {
return false;
} else {
stk.pop();
}
}
return stk.length == 0;
};
function match(l, r) {
return (l == '(' && r == ')') (l == '[' && r == ']') || (l == '{' && r == '}');
}
Пояснение:
Пройдите по строке скобок s. При
обнаружении левой скобки вставьте
текущую левую скобку в стек; при
обнаружении правой скобки извлеките верхний
элемент из стека (если стек пуст,
сразу верните значение false ) и оцените
, соответствует ли оно. Если оно не совпадает, напрямую
верните значение false.
В качестве альтернативы, при обнаружении левой
скобки вы можете поместить соответствующую
правую скобку в стек; при
обнаружении правой скобки извлеките верхний
элемент стека (если стек пуст,
непосредственно верните значение false ) и оцените, равны ли
они. Если они не совпадают,
напрямую верните значение false.
Разница между этими двумя
методами заключается только во времени
преобразования скобок: один - при вставке в стек
, а другой - при
извлечении из стека.
В конце обхода, если стек
пуст, это означает, что строка в скобках верна,
возвращает значение true; в противном случае возвращает значение false.
Временная сложность равна O(n), а
пространственная сложность равна O(n). Здесь n - это
длина строки скобок s.
👍2
Задача: №21. Merge Two Sorted Lists #easy
Условие:
Решение:
Пояснение:
Сначала мы оцениваем, являются ли связанные списки l1
и l2 пустыми. Если один из них пуст,
мы возвращаем другой связанный список. В противном случае
мы сравниваем головные узлы l1 и l2:
• Если значение головного узла из ₁
меньше или равно значению
головного узла из l2, мы рекурсивно вызываем
функцию mergeTwoLists (l1. далее, l2)
и соединяем головной узел из ₁ с
возвращаемым головным узлом связанного списка и
возвращаем головной узел из l1.
• В противном случае мы рекурсивно вызываем
функцию mergeTwoLists (l1, l2. next)
и соединяем головной узел l2 с
возвращаемым головным узлом связанного списка и
возвращаем головной узел l2.
Временная сложность равна O(m + n), а
пространственная - O(m + n). Здесь m
и n - длины двух связанных списков
соответственно.
Условие:
Вам даны заголовки двух отсортированных связанных списков list1 и list2. Объедините два списка в один отсортированный список. Список должен быть составлен путем сращивания узлов первых двух списков. Возвращает заголовок объединенного связанного списка.
Решение:
/
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/
* @param {ListNode} list1
* @param {ListNode} list2
* @return {ListNode}
*/
var mergeTwoLists = function (list1, list2) {
if (!list1 !list2) {
return list1 list2;
}
if (list1.val <= list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
} else {
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
};
Пояснение:
Сначала мы оцениваем, являются ли связанные списки l1
и l2 пустыми. Если один из них пуст,
мы возвращаем другой связанный список. В противном случае
мы сравниваем головные узлы l1 и l2:
• Если значение головного узла из ₁
меньше или равно значению
головного узла из l2, мы рекурсивно вызываем
функцию mergeTwoLists (l1. далее, l2)
и соединяем головной узел из ₁ с
возвращаемым головным узлом связанного списка и
возвращаем головной узел из l1.
• В противном случае мы рекурсивно вызываем
функцию mergeTwoLists (l1, l2. next)
и соединяем головной узел l2 с
возвращаемым головным узлом связанного списка и
возвращаем головной узел l2.
Временная сложность равна O(m + n), а
пространственная - O(m + n). Здесь m
и n - длины двух связанных списков
соответственно.
🔥3🤮1
Задача: №22. Generate Parentheses #medium
Условие:
Пояснение:
Диапазон значений n в задаче равен [1, 8], поэтому
мы можем напрямую решить эту проблему с помощью
"поиска методом перебора + обрезки".
Мы создаем функцию dfs(l,r,t), где I
и представляют количество левых и
правых скобок соответственно, а t
представляет текущую последовательность скобок.
Тогда мы можем получить следующую рекурсивную
структуру:
• Если > n или r > n или l<r, то
текущая комбинация скобок t
недопустима, возвращайте напрямую;
• Если l = n и r = n, то текущая
комбинация скобок t допустима, добавьте ее в
массив ответов ans и возвращайте
напрямую;
• Мы можем добавить левую скобку
и рекурсивно выполнить dfs (1 + 1,
r, t + "(")). ;
• Мы также можем добавить правую
скобку и рекурсивно выполнить
dfs(1, r +1, t + ")").
Временная сложность равна O(2×2 × n), а
пространственная - O(n).
Условие:
Учитывая n пар круглых скобок, напишите функцию, которая генерирует все комбинации правильных круглых скобок.Решение:
/**
* @param {number} n
* @return {string[]}
*/
var generateParenthesis = function (n) {
function dfs(l, r, t) {
if (l > n r > n l < r) {
return;
}
if (l == n && r == n) {
ans.push(t);
return;
}
dfs(l + 1, r, t + '(');
dfs(l, r + 1, t + ')');
}
let ans = [];
dfs(0, 0, '');
return ans;
};
Пояснение:
Диапазон значений n в задаче равен [1, 8], поэтому
мы можем напрямую решить эту проблему с помощью
"поиска методом перебора + обрезки".
Мы создаем функцию dfs(l,r,t), где I
и представляют количество левых и
правых скобок соответственно, а t
представляет текущую последовательность скобок.
Тогда мы можем получить следующую рекурсивную
структуру:
• Если > n или r > n или l<r, то
текущая комбинация скобок t
недопустима, возвращайте напрямую;
• Если l = n и r = n, то текущая
комбинация скобок t допустима, добавьте ее в
массив ответов ans и возвращайте
напрямую;
• Мы можем добавить левую скобку
и рекурсивно выполнить dfs (1 + 1,
r, t + "(")). ;
• Мы также можем добавить правую
скобку и рекурсивно выполнить
dfs(1, r +1, t + ")").
Временная сложность равна O(2×2 × n), а
пространственная - O(n).
🔥2🤮2
Задача: №23. Merge k Sorted Lists #hard
Условие:
Решение:
Пояснение:
Диапазон значений n в задаче равен [1, 8], поэтому
мы можем напрямую решить эту проблему с помощью
"поиска методом перебора + обрезки".
Мы создаем функцию dfs(l,r,t), где I
и представляют количество левых и
правых скобок соответственно, а t
представляет текущую последовательность скобок.
Тогда мы можем получить следующую рекурсивную
структуру:
• Если > n или r > n или l<r, то
текущая комбинация скобок t
недопустима, возвращайте напрямую;
• Если l = n и r = n, то текущая
комбинация скобок t допустима, добавьте ее в
массив ответов ans и возвращайте
напрямую;
• Мы можем добавить левую скобку
и рекурсивно выполнить dfs (1 + 1,
r, t + "(")). ;
• Мы также можем добавить правую
скобку и рекурсивно выполнить
dfs(1, r +1, t + ")").
Временная сложность равна O(2×2 × n), а
пространственная - O(n).
Условие:
Вам дан массив из k списков связанных списков, каждый связанный список отсортирован в порядке возрастания. Объедините все связанные списки в один отсортированный связанный список и верните его.
Решение:
/
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/
* @param {ListNode[]} lists
* @return {ListNode}
*/
var mergeKLists = function (lists) {
const pq = new MinPriorityQueue({ priority: node => node.val });
for (const head of lists) {
if (head) {
pq.enqueue(head);
}
}
const dummy = new ListNode();
let cur = dummy;
while (!pq.isEmpty()) {
const node = pq.dequeue().element;
cur.next = node;
cur = cur.next;
if (node.next) {
pq.enqueue(node.next);
}
}
return dummy.next;
};
Пояснение:
Диапазон значений n в задаче равен [1, 8], поэтому
мы можем напрямую решить эту проблему с помощью
"поиска методом перебора + обрезки".
Мы создаем функцию dfs(l,r,t), где I
и представляют количество левых и
правых скобок соответственно, а t
представляет текущую последовательность скобок.
Тогда мы можем получить следующую рекурсивную
структуру:
• Если > n или r > n или l<r, то
текущая комбинация скобок t
недопустима, возвращайте напрямую;
• Если l = n и r = n, то текущая
комбинация скобок t допустима, добавьте ее в
массив ответов ans и возвращайте
напрямую;
• Мы можем добавить левую скобку
и рекурсивно выполнить dfs (1 + 1,
r, t + "(")). ;
• Мы также можем добавить правую
скобку и рекурсивно выполнить
dfs(1, r +1, t + ")").
Временная сложность равна O(2×2 × n), а
пространственная - O(n).
👍1
Задача: №24. Swap Nodes in Pairs #medium
Условие:
Решение:
Пояснение:
Мы можем реализовать замену двух узлов в связанном списке с помощью рекурсии.
Условием завершения рекурсии является отсутствие узлов в связанном списке или наличие только одного узла в связанном списке. В данный момент замена не может быть выполнена, поэтому мы возвращаем этот узел напрямую.
В противном случае мы рекурсивно меняем заголовок связанного списка местами. следующий. далее, и пусть замененный головной узел будет t. Затем мы позволяем p быть следующим узлом head, и пусть p указывает на head, а head указывает на t, и, наконец, возвращаем p.
Временная сложность равна O(n), а пространственная - O(n). Здесь n - длина связанного списка.
Условие:
Учитывая связанный список, поменяйте местами каждые два соседних узла и верните его голову. Вы должны решить проблему, не изменяя значения в узлах списка (т. е. изменять можно только сами узлы).
Решение:
/
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/
* @param {ListNode} head
* @return {ListNode}
*/
var swapPairs = function (head) {
if (!head || !head.next) {
return head;
}
const t = swapPairs(head.next.next);
const p = head.next;
p.next = head;
head.next = t;
return p;
};
Пояснение:
Мы можем реализовать замену двух узлов в связанном списке с помощью рекурсии.
Условием завершения рекурсии является отсутствие узлов в связанном списке или наличие только одного узла в связанном списке. В данный момент замена не может быть выполнена, поэтому мы возвращаем этот узел напрямую.
В противном случае мы рекурсивно меняем заголовок связанного списка местами. следующий. далее, и пусть замененный головной узел будет t. Затем мы позволяем p быть следующим узлом head, и пусть p указывает на head, а head указывает на t, и, наконец, возвращаем p.
Временная сложность равна O(n), а пространственная - O(n). Здесь n - длина связанного списка.
👍1
Задача: №26.Remove Duplicates from Sorted Array #easy
Условие:
Решение:
Пояснение:
Мы используем переменную k для записи текущей длины обрабатываемого массива. Изначально
значение k = 0 представляет пустой массив.
Затем мы проходим по массиву слева направо. Для каждого элемента x, с которым мы сталкиваемся, если
k = 0 или x != nums|k - 1], мы помещаем x в позицию nums|k|, а затем увеличиваем k на 1. В противном случае значение x совпадает с значением nums|k - 1], поэтому мы пропускаем этот элемент.
Продолжайте обход, пока не будет пройден весь массив.
Таким образом, когда обход завершается, первые k элементов в числах являются ответом, который мы ищем, а k - это длина ответа.
Временная сложность равна O(n), а пространственная сложность равна O(1). Здесь n - это длина массива.
Дополнение:
Исходная задача требует, чтобы одно и то же число появлялось не более одного раза. Мы можем расширить ее, чтобы сохранить не более k одинаковых чисел.
Поскольку одно и то же число может сохраняться не более k раз, мы можем напрямую сохранить первые k элементов исходного массива;
Для следующих чисел предпосылка их сохранения такова: текущее число x сравнивается с последним k-м элементом из ранее сохраненных чисел. Если они отличаются друг от друга, сохраните их, в противном случае пропустите.
Условие:
При наличии целочисленного массива nums, отсортированного в порядке неубывания, удалите дубликаты на месте, чтобы каждый уникальный элемент отображался только один раз. Относительный порядок элементов должен оставаться неизменным. Затем верните количество уникальных элементов в nums. Предположим, что количество уникальных элементов nums равно k, для того, чтобы их приняли, вам нужно выполнить следующие действия: Измените массив nums таким образом, чтобы первые k элементов nums содержали уникальные элементы в том порядке, в котором они изначально присутствовали в nums. Остальные элементы nums не важны, так же как и размер nums.
Верните k.
Решение:
/**
* @param {number[]} nums
* @return {number}
*/
var removeDuplicates = function (nums) {
let k = 0;
for (const x of nums) {
if (k === 0 || x !== nums[k - 1]) {
nums[k++] = x;
}
}
return k;
};
Пояснение:
Мы используем переменную k для записи текущей длины обрабатываемого массива. Изначально
значение k = 0 представляет пустой массив.
Затем мы проходим по массиву слева направо. Для каждого элемента x, с которым мы сталкиваемся, если
k = 0 или x != nums|k - 1], мы помещаем x в позицию nums|k|, а затем увеличиваем k на 1. В противном случае значение x совпадает с значением nums|k - 1], поэтому мы пропускаем этот элемент.
Продолжайте обход, пока не будет пройден весь массив.
Таким образом, когда обход завершается, первые k элементов в числах являются ответом, который мы ищем, а k - это длина ответа.
Временная сложность равна O(n), а пространственная сложность равна O(1). Здесь n - это длина массива.
Дополнение:
Исходная задача требует, чтобы одно и то же число появлялось не более одного раза. Мы можем расширить ее, чтобы сохранить не более k одинаковых чисел.
Поскольку одно и то же число может сохраняться не более k раз, мы можем напрямую сохранить первые k элементов исходного массива;
Для следующих чисел предпосылка их сохранения такова: текущее число x сравнивается с последним k-м элементом из ранее сохраненных чисел. Если они отличаются друг от друга, сохраните их, в противном случае пропустите.
👍4🤯2
Задача: №27.Remove Element #easy
Условие:
Решение:
Пояснение:
Мы используем переменную k для записи количества элементов, которые не равны val.
Проходим по массиву nums, если текущий элемент x не равен val, затем присваиваем x значение nums|k) и увеличиваем k на 1.
Наконец, возвращаем k.
Временная сложность равна O(n), а пространственная - O(1), где n - длина массива nums.
Условие:
Учитывая целочисленный массив nums и целое значение val, удалите все вхождения val в nums на месте. Порядок элементов может быть изменен. Затем верните количество элементов в nums, которые не равны val. Учтите, что количество элементов в nums, которые не равны val, равно k, чтобы их приняли, вам нужно выполнить следующие действия: Измените массив nums таким образом, чтобы первые k элементов в nums содержали элементы, которые не равны val. Остальные элементы nums не важны, так же как и размер nums. Верните k.
Решение:
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function (nums, val) {
let k = 0;
for (const x of nums) {
if (x !== val) {
nums[k++] = x;
}
}
return k;
};
Пояснение:
Мы используем переменную k для записи количества элементов, которые не равны val.
Проходим по массиву nums, если текущий элемент x не равен val, затем присваиваем x значение nums|k) и увеличиваем k на 1.
Наконец, возвращаем k.
Временная сложность равна O(n), а пространственная - O(1), где n - длина массива nums.
❤2
Задача: 28. Find the Index of the First Occurrence in a String #easy
Условие:
Решение:
Пояснение:
1. Функция strStr принимает две строки: haystack - строку, в которой нужно найти подстроку, и needle - подстроку, которую нужно найти.
2. Сначала функция проверяет, если needle пустая строка, то возвращает 0, так как подстрока пустая и она есть в любой строке на любой позиции.
3. Далее функция использует цикл for, чтобы пройтись по каждому символу в строке haystack.
4. На каждой итерации цикла, функция создает подстроку haySlice, начиная с текущей позиции i и длиной подстроки needle.
5. Затем происходит сравнение подстроки haySlice с needle. Если они равны, функция возвращает индекс i, то есть позицию, с которой начинается найденная подстрока needle в строке haystack.
6. Если подстрока haySlice не равна needle, цикл продолжает итерироваться через строку haystack.
7. Если не удалось найти подстроку needle в строке haystack, функция возвращает -1, указывая на отсутствие искомой подстроки в строке.
Условие:
Учитывая две строки, игла и стог сена, верните индекс первого вхождения иглы в стоге сена или -1, если игла не является частью стога сена.
Решение:
function strStr(haystack, needle) { if (needle === "") {
return 0; }
for (let i = 0; i < haystack.length; i++) {
let haySlice = haystack.slice(i, i + needle.length); if (haySlice === needle) {
return i; }
} return -1;
}Пояснение:
1. Функция strStr принимает две строки: haystack - строку, в которой нужно найти подстроку, и needle - подстроку, которую нужно найти.
2. Сначала функция проверяет, если needle пустая строка, то возвращает 0, так как подстрока пустая и она есть в любой строке на любой позиции.
3. Далее функция использует цикл for, чтобы пройтись по каждому символу в строке haystack.
4. На каждой итерации цикла, функция создает подстроку haySlice, начиная с текущей позиции i и длиной подстроки needle.
5. Затем происходит сравнение подстроки haySlice с needle. Если они равны, функция возвращает индекс i, то есть позицию, с которой начинается найденная подстрока needle в строке haystack.
6. Если подстрока haySlice не равна needle, цикл продолжает итерироваться через строку haystack.
7. Если не удалось найти подстроку needle в строке haystack, функция возвращает -1, указывая на отсутствие искомой подстроки в строке.
❤4
Задача: 29. Divide Two Integers #medium
Условие:
Решение:
Пояснение:
1. Функция divide определяется как анонимная функция, принимающая два аргумента dividend и divisor.
2. Проверяется условие, если dividend равен 0, то сразу возвращается 0, так как деление на ноль равно 0.
3. Создается переменная signal со значением 1, которая будет использоваться для определения знака результата.
4. Если dividend меньше 0, знак signal умножается на -1, чтобы сохранить отрицательный результат.
5. Аналогично, если divisor меньше 0, знак signal также умножается на -1.
6. Затем модулируются dividend и divisor, чтобы оба значения стали положительными.
7. В переменной result сохраняется результат вызова вспомогательной функции help с аргументами dividend и divisor, умноженный на знак signal.
8. После вычислений результата проверяется его на соответствие диапазону значений для 32-битного целого числа, и при необходимости результат обрезается до максимальных или минимальных значений.
9. Возвращается итоговый результат деления.
10. Внутри функции divide определена вспомогательная рекурсивная функция help, которая выполняет деление с использованием алгоритма разделяй и властвуй.
11. Функция help рекурсивно вызывается до тех пор, пока dividend не станет меньше divisor.
12. На каждой итерации цикла в help увеличивается счетчик res, который дает количество раз, на которое divisor полностью помещается в dividend.
13. Рекурсивным вызовом help обрабатывается остаток от деления dividend на исходный divisor.
Условие:
Учитывая два целых числа: делимое и делитель, разделите два целых числа, не используя операторы умножения, деления и модификатора.
Целочисленное деление должно сокращаться до нуля, что означает потерю дробной части. Например, 8,345 будет сокращено до 8, а -2,7335 будет сокращено до -2.
Возвращает частное после деления делимого на делитель.
Примечание. Предположим, мы имеем дело со средой, которая может хранить целые числа только в пределах 32-битного целого диапазона со знаком: [−2^31, 2^31 − 1]. В этой задаче, если частное строго больше 2^31 - 1, верните 2^31 - 1, а если частное строго меньше -2^31, верните -2^31.
Решение:
var divide = function(dividend, divisor) { if(dividend===0) return 0;
let signal = 1; if(dividend<0){
signal *= -1; }
if(divisor<0){ signal *= -1;
} dividend = Math.abs(dividend);
divisor = Math.abs(divisor);
let result = help(dividend, divisor)*signal; if(result>Math.pow(2,31)-1){
result = Math.pow(2,31)-1; }else if(result<-1*Math.pow(2,31)){
result = Math.pow(2,31)*(-1); }
return result;
function help(dividend, divisor){ if(dividend < divisor) return 0;
let res = 0; let origDivisor = divisor;
let prev = 0; while(dividend>=divisor){
if(res===0){ res += 1;
}else{ res += res;
} prev = divisor;
divisor += divisor; }
dividend -= prev; res += help(dividend, origDivisor);
return res; }
};Пояснение:
1. Функция divide определяется как анонимная функция, принимающая два аргумента dividend и divisor.
2. Проверяется условие, если dividend равен 0, то сразу возвращается 0, так как деление на ноль равно 0.
3. Создается переменная signal со значением 1, которая будет использоваться для определения знака результата.
4. Если dividend меньше 0, знак signal умножается на -1, чтобы сохранить отрицательный результат.
5. Аналогично, если divisor меньше 0, знак signal также умножается на -1.
6. Затем модулируются dividend и divisor, чтобы оба значения стали положительными.
7. В переменной result сохраняется результат вызова вспомогательной функции help с аргументами dividend и divisor, умноженный на знак signal.
8. После вычислений результата проверяется его на соответствие диапазону значений для 32-битного целого числа, и при необходимости результат обрезается до максимальных или минимальных значений.
9. Возвращается итоговый результат деления.
10. Внутри функции divide определена вспомогательная рекурсивная функция help, которая выполняет деление с использованием алгоритма разделяй и властвуй.
11. Функция help рекурсивно вызывается до тех пор, пока dividend не станет меньше divisor.
12. На каждой итерации цикла в help увеличивается счетчик res, который дает количество раз, на которое divisor полностью помещается в dividend.
13. Рекурсивным вызовом help обрабатывается остаток от деления dividend на исходный divisor.
🤯5❤2
Задача: 30. Substring with Concatenation of All Words #hard
Условие:
Пояснение:
1. В функции findSubstring сначала определяется длина len первого слова из массива words и общий размер окна windowSize для всех слов из массива. Если длина входной строки s меньше размера окна, то функция возвращает пустой массив.
2. Создается пустая хэш-таблица m для хранения количества вхождений каждого слова из массива words и массив res для хранения индексов начала подстроки в строке s.
3. Заполняется хэш-таблица m с записями вида (слово, количество вхождений) для каждого слова из массива words.
4. Далее производится поэлементный обход строки s с шагом 1, начиная с индекса start. Для каждой итерации проверяется, является ли подстрока с текущим окном возможной конкатенацией слов из массива words с помощью функции isConcat.
5. Если проверка в isConcat возвращает true, текущий индекс start добавляется в массив res как начало валидной подстроки.
6. После завершения обхода возвращается массив res, содержащий индексы начала валидных подстрок в строке s.
7. Вспомогательная функция isConcat проверяет, является ли данная подстрока валидной конкатенацией слов из хэш-таблицы m. Она обходит подстроку с шагом len, уменьшая количество оставшихся вхождений для каждого слова в хэш-таблице, пока не исчерпаются все слова. Функция возвращает true в случае успешного поиска, иначе false.
8. Общая сложность времени для функции findSubstring равна O(M*N), где M - длина входной строки s, N - количество слов в массиве words, а пространственная сложность составляет O(M*N) из-за использования новой хэш-таблицы на каждой итерации. Функция isConcat имеет линейную сложность от размера окна N.
Условие:
Вам дана строка s и массив строк-слов. Все строки слов имеют одинаковую длину.Решение:
Объединенная строка — это строка, которая в точности содержит все строки любой перестановки объединенных слов.
Например, если слова = ["ab", "cd", "ef"], то "abcdef", "abefcd", "cdabef", "cdefab", "efabcd" и "efcdab" являются объединенными строками. «acdbef» не является объединенной строкой, поскольку не является объединением какой-либо перестановки слов.Возвращает массив начальных индексов всех объединенных подстрок в s. Вы можете вернуть ответ в любом порядке.
var findSubstring = function(s, words) {
let len = words[0].length; let windowSize = words.length * len;
if (s.length < windowSize) { return [];
} let m = new Map(), res = [];
// Fill Hash table with entry being (word, number of occurrences) for (let i = 0; i < words.length; i++) {
m.set(words[i], m.get(words[i]) + 1 1); }
let start = 0; while (start + windowSize - 1 < s.length) {
if (isConcat(s, new Map(m), len, start, start + windowSize-1)) { res.push(start);
} start++;
} return res;
// Let M be the length of s, N be the number of words // T.C: O(M*N)
// S.C: O(M*N), new map is used for every iteration};
const isConcat = (s, m, len, start, end) => {
let chars = m.size; for (let i = start; i <= end; i += len) {
let substr = s.substring(i, i+len); if (!m.has(substr) m.get(substr) === 0) return false;
m.set(substr, m.get(substr) - 1); if (m.get(substr) === 0) {
chars--; }
} return chars === 0;
// if we consider time complexity of substring() to be O(1), // T.C: O(N)
}Пояснение:
1. В функции findSubstring сначала определяется длина len первого слова из массива words и общий размер окна windowSize для всех слов из массива. Если длина входной строки s меньше размера окна, то функция возвращает пустой массив.
2. Создается пустая хэш-таблица m для хранения количества вхождений каждого слова из массива words и массив res для хранения индексов начала подстроки в строке s.
3. Заполняется хэш-таблица m с записями вида (слово, количество вхождений) для каждого слова из массива words.
4. Далее производится поэлементный обход строки s с шагом 1, начиная с индекса start. Для каждой итерации проверяется, является ли подстрока с текущим окном возможной конкатенацией слов из массива words с помощью функции isConcat.
5. Если проверка в isConcat возвращает true, текущий индекс start добавляется в массив res как начало валидной подстроки.
6. После завершения обхода возвращается массив res, содержащий индексы начала валидных подстрок в строке s.
7. Вспомогательная функция isConcat проверяет, является ли данная подстрока валидной конкатенацией слов из хэш-таблицы m. Она обходит подстроку с шагом len, уменьшая количество оставшихся вхождений для каждого слова в хэш-таблице, пока не исчерпаются все слова. Функция возвращает true в случае успешного поиска, иначе false.
8. Общая сложность времени для функции findSubstring равна O(M*N), где M - длина входной строки s, N - количество слов в массиве words, а пространственная сложность составляет O(M*N) из-за использования новой хэш-таблицы на каждой итерации. Функция isConcat имеет линейную сложность от размера окна N.
👍7❤5🤯4
Задача: 31. Next Permutation #medium
Условие:
Решение:
Пояснение:
1. Сначала устанавливаем переменные i, j и k в конечные позиции массива nums для последующего использования в алгоритме.
2. Затем начинаем поиск позиции i, такой, что nums[i] < nums[j], двигаясь с конца массива к началу. Это позволит нам найти элемент, который нужно поменять местами.
3. Если i >= 0, то нашли такую позицию i. Иначе, если i < 0, значит массив nums является убывающей последовательностью, например, 321.
4. Далее находим позицию k в интервале [j, конец], где nums[k] чуть больше nums[i]. Это необходимо для нахождения элемента, который мы будем менять местами с nums[i].
5. После нахождения позиций i и k, производим обмен элементов nums[i] и nums[k].
6. После обмена выполняем операцию "переворота" (перестановка в обратном порядке) в интервале [j, конец], так как это участок массива был убывающим и должен стать возрастающим.
7. Функция twoPointerReverse используется для переворота этих элементов в интервале [j, конец], где left и right - указатели на начало и конец интервала соответственно.
8. В конце функция возвращает измененный массив nums с новой перестановкой.
Условие:
Перестановка массива целых чисел — это расположение его членов в последовательность или линейный порядок.
Например, для arr = [1,2,3] следующие перестановки arr: [1,2,3], [1,3,2], [2, 1, 3], [2, 3, 1], [3,1,2], [3,2,1].Следующая перестановка массива целых чисел — это следующая лексикографически большая перестановка его целого числа. Более формально, если все перестановки массива отсортированы в одном контейнере в соответствии с их лексикографическим порядком, то следующей перестановкой этого массива будет перестановка, следующая за ней в отсортированном контейнере. Если такое расположение невозможно, массив необходимо переупорядочить в наименьшем возможном порядке (т. е. отсортировать по возрастанию).
Учитывая массив целых чисел nums, найдите следующую перестановку чисел.
Замена должна быть на месте и использовать только постоянную дополнительную память.
Решение:
var nextPermutation = function(nums) {
const len = nums.length;
let i = len - 2, j = len - 1, k = len - 1;
while (i >= 0 && nums[i] >= nums[j]) {
i--;
j--;
}
if (i >= 0) {
while (nums[i] >= nums[k]) {
k--;
}
[nums[i], nums[k]] = [nums[k], nums[i]];
}
twoPointerReverse(j, len-1, nums);
return nums;
function twoPointerReverse(left, right, nums) {
while (left < right) {
let tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
left++;
right--;
}
}
};Пояснение:
1. Сначала устанавливаем переменные i, j и k в конечные позиции массива nums для последующего использования в алгоритме.
2. Затем начинаем поиск позиции i, такой, что nums[i] < nums[j], двигаясь с конца массива к началу. Это позволит нам найти элемент, который нужно поменять местами.
3. Если i >= 0, то нашли такую позицию i. Иначе, если i < 0, значит массив nums является убывающей последовательностью, например, 321.
4. Далее находим позицию k в интервале [j, конец], где nums[k] чуть больше nums[i]. Это необходимо для нахождения элемента, который мы будем менять местами с nums[i].
5. После нахождения позиций i и k, производим обмен элементов nums[i] и nums[k].
6. После обмена выполняем операцию "переворота" (перестановка в обратном порядке) в интервале [j, конец], так как это участок массива был убывающим и должен стать возрастающим.
7. Функция twoPointerReverse используется для переворота этих элементов в интервале [j, конец], где left и right - указатели на начало и конец интервала соответственно.
8. В конце функция возвращает измененный массив nums с новой перестановкой.
🤯7👍4✍1
Задача: 32. Longest Valid Parentheses #hard
Условие:
Решение:
Пояснение:
1. Создаётся функция longestValidParentheses, которая принимает строку s в качестве аргумента.2. Вычисляется длина строки s и создаётся массив S с начальным элементом -1 и переменная x для хранения длины самой длинной правильной скобочной последовательности.
3. Происходит итерация по символам строки s. Если текущий символ - это открывающая скобка (, то индекс текущего символа добавляется в массив S, что помечает начало текущей возможной последовательности скобок.4. Если текущий символ - это закрывающая скобка ), то удаляется последний элемент из массива S, что соответствует удалению начального индекса открывающей скобки.
5. Проверяется длина массива S. Если он пустой (после удаления всех открывающих скобок), то текущий индекс добавляется обратно в массив S, что обычно указывает на начало новой последовательности скобок.6. Если массив S не пустой после удаления открывающей скобки, то вычисляется длина текущей валидной скобочной последовательности и обновляется переменная x с максимальным значением.
7. В конце выполнения итерации возвращается значение x, которое представляет собой длину самой длинной правильной скобочной последовательности в строке s.
Условие:
Учитывая строку, содержащую только символы «(» и «)», верните длину самых длинных допустимых (правильно сформированных) круглых скобок. подстрока
Решение:
var longestValidParentheses = function(s) {
const n = s.length; const S = [-1];
let x = 0; for (let i = 0; i < n; ++i)
if (s[i] === '(') S.push(i); // open; mark start index
else { S.pop(); // close; remove a start index
if (!S.length) S.push(i); // invalid; reset index to new start
else x = Math.max(x, i - S[S.length - 1]); // valid; save the length
} return x;
};Пояснение:
1. Создаётся функция longestValidParentheses, которая принимает строку s в качестве аргумента.2. Вычисляется длина строки s и создаётся массив S с начальным элементом -1 и переменная x для хранения длины самой длинной правильной скобочной последовательности.
3. Происходит итерация по символам строки s. Если текущий символ - это открывающая скобка (, то индекс текущего символа добавляется в массив S, что помечает начало текущей возможной последовательности скобок.4. Если текущий символ - это закрывающая скобка ), то удаляется последний элемент из массива S, что соответствует удалению начального индекса открывающей скобки.
5. Проверяется длина массива S. Если он пустой (после удаления всех открывающих скобок), то текущий индекс добавляется обратно в массив S, что обычно указывает на начало новой последовательности скобок.6. Если массив S не пустой после удаления открывающей скобки, то вычисляется длина текущей валидной скобочной последовательности и обновляется переменная x с максимальным значением.
7. В конце выполнения итерации возвращается значение x, которое представляет собой длину самой длинной правильной скобочной последовательности в строке s.
👍3
Задача: 33. Search in Rotated Sorted Array #medium
Условие:
Решение:
Пояснение:
1. Объявление функции search, которая принимает массив чисел nums и целевое число target в качестве аргументов.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. В теле функции начинается выполнение:
- Создается переменная res, которая содержит индекс первого вхождения целевого числа target в массиве nums. Функция indexOf возвращает -1, если значение не найдено.
- Далее выполняется проверка if, где мы первоначально проверяем res как булево значение свойства объекта. Если индекс числа target был найден (не равен -1), то значение res будет истинным и мы возвращаем его. - В случае, если res равно -1, что означает, что число target не найдено в массиве, мы возвращаем -1.
- Если ни одно из предыдущих условий не сработало, это означает, что res содержит индекс числа target, и мы возвращаем его.
4. Выполнение функции завершается возвратом соответствующего значения: индекса числа target, -1 в случае его отсутствия или индекса числа target в противном случае.
5. Этот код проверяет наличие целевого числа в массиве и возвращает его индекс в случае нахождения, -1 в случае отсутствия числа. Однако стоит отметить, что внутри if (res) res будет равен 0 (индекс первого элемента), а это может быть истолковано как false, что может привести к неправильной работе функции при значении target равном 0. Необходимо учесть этот момент при работе с функцией.
Условие:
Существует целочисленный массив nums, отсортированный по возрастанию (с разными значениями).
Перед передачей в вашу функцию nums, возможно, поворачивается с неизвестным индексом поворота k (1 <= k < nums.length), так что результирующий массив имеет вид [nums[k], nums[k+1],... , nums[n-1], nums[0], nums[1], ..., nums[k-1]] (с индексом 0). Например, [0,1,2,4,5,6,7] можно повернуть с опорным индексом 3 и превратить в [4,5,6,7,0,1,2].
Учитывая массив nums после возможного поворота и целочисленную цель, верните индекс цели, если он находится в nums, или -1, если он не в nums.
Вы должны написать алгоритм со сложностью выполнения O(log n).
Решение:
/** * @param {number[]} nums
* @param {number} target * @return {number}
*/var search = function(nums, target) {
let res=nums.indexOf(target);
if(res){ return res;
} else if(res==-1)
{ return -1;
} else{
return res; }
};Пояснение:
1. Объявление функции search, которая принимает массив чисел nums и целевое число target в качестве аргументов.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. В теле функции начинается выполнение:
- Создается переменная res, которая содержит индекс первого вхождения целевого числа target в массиве nums. Функция indexOf возвращает -1, если значение не найдено.
- Далее выполняется проверка if, где мы первоначально проверяем res как булево значение свойства объекта. Если индекс числа target был найден (не равен -1), то значение res будет истинным и мы возвращаем его. - В случае, если res равно -1, что означает, что число target не найдено в массиве, мы возвращаем -1.
- Если ни одно из предыдущих условий не сработало, это означает, что res содержит индекс числа target, и мы возвращаем его.
4. Выполнение функции завершается возвратом соответствующего значения: индекса числа target, -1 в случае его отсутствия или индекса числа target в противном случае.
5. Этот код проверяет наличие целевого числа в массиве и возвращает его индекс в случае нахождения, -1 в случае отсутствия числа. Однако стоит отметить, что внутри if (res) res будет равен 0 (индекс первого элемента), а это может быть истолковано как false, что может привести к неправильной работе функции при значении target равном 0. Необходимо учесть этот момент при работе с функцией.
👍3👀2❤1
Задача: 34. Find First and Last Position of Element in Sorted Array #medium
Условие:
Решение:
Пояснение:
1. Объявление функции searchRange, которая принимает массив чисел nums и целевое число target в качестве аргументов.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. В теле функции происходит выполнение следующих действий: - Функция indexOf(target) возвращает индекс первого вхождения целевого числа target в массиве nums.
- Функция lastIndexOf(target) возвращает индекс последнего вхождения целевого числа target в массиве nums. - Оба индекса (первого и последнего вхождения числа target) затем помещаются в новый массив, который затем возвращается как результат работы функции.
4. После выполнения поиска индексов первого и последнего вхождения числа target в массиве, функция возвращает массив с двумя элементами: индекс первого вхождения и индекс последнего вхождения числа target.
5. Этот код помогает быстро найти и вернуть индексы первого и последнего вхождения целевого числа target в массиве nums. Это может быть полезно, если нужно найти все интервалы, в которых встречается целевое число.
🖥 1429 вопроса на Frontend разработчика
🔒 База собесов | 🔒 База тестовых
Условие:
Учитывая массив целых чисел, отсортированных в порядке неубывания, найдите начальную и конечную позицию заданного целевого значения.
Если цель не найдена в массиве, верните [-1, -1].
Вы должны написать алгоритм со сложностью выполнения O(log n).
Решение:
/** * @param {number[]} nums
* @param {number} target * @return {number[]}
*/var searchRange = function(nums, target) {
return [nums.indexOf(target), nums.lastIndexOf(target)]
};Пояснение:
1. Объявление функции searchRange, которая принимает массив чисел nums и целевое число target в качестве аргументов.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. В теле функции происходит выполнение следующих действий: - Функция indexOf(target) возвращает индекс первого вхождения целевого числа target в массиве nums.
- Функция lastIndexOf(target) возвращает индекс последнего вхождения целевого числа target в массиве nums. - Оба индекса (первого и последнего вхождения числа target) затем помещаются в новый массив, который затем возвращается как результат работы функции.
4. После выполнения поиска индексов первого и последнего вхождения числа target в массиве, функция возвращает массив с двумя элементами: индекс первого вхождения и индекс последнего вхождения числа target.
5. Этот код помогает быстро найти и вернуть индексы первого и последнего вхождения целевого числа target в массиве nums. Это может быть полезно, если нужно найти все интервалы, в которых встречается целевое число.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Задача: 35. Search Insert Position #easy
Условие:
Решение:
Пояснение:
1. Объявление функции searchInsert, которая принимает массив чисел nums и целевое число target в качестве аргументов.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. В теле функции выполняются следующие действия: - Проверяется, есть ли целевое число target в массиве nums. Если его индекс равен -1 (то есть он не найден), выполняется следующее:
- Начинается цикл for, который проверяет каждый элемент массива nums. - Если текущий элемент nums[i] меньше целевого числа target, индекс i увеличивается.
- Если текущий элемент nums[i] больше или равен целевому числу target, функция возвращает текущий индекс i. - Если целевое число target найдено в массиве, функция возвращает его индекс, найденный с помощью indexOf.
4. После выполнения поиска индекса для вставки числа target в массив, функция возвращает индекс, указывающий позицию, на которую нужно вставить целевое число.
5. Этот код помогает найти позицию для вставки целевого числа target в упорядоченный массив nums. Если число target уже присутствует в массиве, возвращается его индекс; в противном случае возвращается индекс, указывающий позицию для вставки target так, чтобы массив оставался упорядоченным.
Условие:
Учитывая отсортированный массив различных целых чисел и целевое значение, верните индекс, если цель найдена. Если нет, верните индекс там, где он был бы, если бы он был вставлен по порядку.
Вы должны написать алгоритм со сложностью выполнения O(log n).
Решение:
/** * @param {number[]} nums
* @param {number} target * @return {number}
*/var searchInsert = function(nums, target) {
if (nums.indexOf(target) === -1) { for (let i = 0; i <= nums.length; ) {
if (nums[i] < target) { i++;
} else { return i
} }
} else { return nums.indexOf(target);
}};Пояснение:
1. Объявление функции searchInsert, которая принимает массив чисел nums и целевое число target в качестве аргументов.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. В теле функции выполняются следующие действия: - Проверяется, есть ли целевое число target в массиве nums. Если его индекс равен -1 (то есть он не найден), выполняется следующее:
- Начинается цикл for, который проверяет каждый элемент массива nums. - Если текущий элемент nums[i] меньше целевого числа target, индекс i увеличивается.
- Если текущий элемент nums[i] больше или равен целевому числу target, функция возвращает текущий индекс i. - Если целевое число target найдено в массиве, функция возвращает его индекс, найденный с помощью indexOf.
4. После выполнения поиска индекса для вставки числа target в массив, функция возвращает индекс, указывающий позицию, на которую нужно вставить целевое число.
5. Этот код помогает найти позицию для вставки целевого числа target в упорядоченный массив nums. Если число target уже присутствует в массиве, возвращается его индекс; в противном случае возвращается индекс, указывающий позицию для вставки target так, чтобы массив оставался упорядоченным.
❤1
Задача: 36. Valid Sudoku #medium
Условие:
Решение:
Пояснение:
1. Объявление функции isValidSudoku, принимающей двумерный массив board, представляющий судоку.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. Создание трех Map (rowMap, colmMap, grid33) для отслеживания уникальности значений в строках, столбцах и 3x3 квадратах судоку.
4. Внешний цикл for от 0 до 8 для перебора строк судоку.
5. Внутренний цикл for от 0 до 8 для перебора ячеек в строке:
- Вычисление индекса m текущей ячейки в 3x3 квадрате. - Проверка условий для строки, столбца и 3x3 квадрата:
- Если значение board[i][j] еще не встречалось в rowMap или равно '.', оно добавляется в rowMap. - Если значение board[j][i] еще не встречалось в colmMap или равно '.', оно добавляется в colmMap.
- Если значение m еще не встречалось в grid33 или равно '.', оно добавляется в grid33. - Если значение уже встречалось, возвращается false.
6. После проверки каждой строки, значения в rowMap, colmMap, grid33 очищаются для следующей итерации.
7. По завершении всех итераций по строкам, если все значения уникальны, функция возвращает true, иначе false.
Этот код проверяет, является ли судоку действительным. Если все условия для уникальности значений в строках, столбцах и 3x3 квадратах выполняются, функция возвращает true. В противном случае возвращается false.
Условие:
Определите, действительна ли доска для судоку 9 x 9. Только заполненные ячейки подлежат проверке согласно следующим правилам:
Каждая строка должна содержать цифры от 1 до 9 без повторений.Каждый столбец должен содержать цифры 1–9 без повторений.
Каждый из девяти подполей сетки размером 3х3 должен содержать цифры от 1 до 9 без повторений.Примечание:
Доска судоку (частично заполненная) может быть допустимой, но не обязательно решаемой.
Только заполненные ячейки должны быть проверены в соответствии с указанными правилами.
Решение:
/**
* @param {character[][]} board * @return {boolean}
*/var isValidSudoku = function(board) {
let rowMap = new Map(); let colmMap = new Map();
let grid33 = new Map();
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++){ let m = board[3 * Math.floor(i / 3) + Math.floor(j / 3)][((i * 3) % 9) + (j % 3)]
if(!rowMap.get(board[i][j]) board[i][j] == '.' ) { rowMap.set(board[i][j], 1)
} else { return false}
if (!colmMap.get(board[j][i]) board[j][i] == '.' ) { colmMap.set(board[j][i], 1)
} else { return false}
if (!grid33.get(m) || m == '.'){ grid33.set(m, 1)
} else { return false}
} rowMap.clear();
grid33.clear(); colmMap.clear();
} return true
};
Пояснение:
1. Объявление функции isValidSudoku, принимающей двумерный массив board, представляющий судоку.
2. В комментарии указаны типы аргументов и возвращаемое значение функции.
3. Создание трех Map (rowMap, colmMap, grid33) для отслеживания уникальности значений в строках, столбцах и 3x3 квадратах судоку.
4. Внешний цикл for от 0 до 8 для перебора строк судоку.
5. Внутренний цикл for от 0 до 8 для перебора ячеек в строке:
- Вычисление индекса m текущей ячейки в 3x3 квадрате. - Проверка условий для строки, столбца и 3x3 квадрата:
- Если значение board[i][j] еще не встречалось в rowMap или равно '.', оно добавляется в rowMap. - Если значение board[j][i] еще не встречалось в colmMap или равно '.', оно добавляется в colmMap.
- Если значение m еще не встречалось в grid33 или равно '.', оно добавляется в grid33. - Если значение уже встречалось, возвращается false.
6. После проверки каждой строки, значения в rowMap, colmMap, grid33 очищаются для следующей итерации.
7. По завершении всех итераций по строкам, если все значения уникальны, функция возвращает true, иначе false.
Этот код проверяет, является ли судоку действительным. Если все условия для уникальности значений в строках, столбцах и 3x3 квадратах выполняются, функция возвращает true. В противном случае возвращается false.
❤1
Задача: 38. Count and Say #medium
Условие:
Решение:
Пояснение:
1. Базовый случай:
- Если `n` равен 1, то функция возвращает "1" - это первая строка последовательности.
2. Инициализация:
- `ans` - строка, которая будет хранить результат генерации следующей строки.
- `temp` - строка, которая хранит предыдущую строку. Изначально она равна "1".
3. Цикл для генерации строк:
- Цикл `for` выполняется `n-1` раз, чтобы сгенерировать строки с 2-й по `n`-ю.
- Внутри цикла:
- `cnt` - счетчик, который хранит количество повторений текущего символа.
- `prev` - предыдущий символ, который мы обрабатываем.
4. Генерация следующей строки:
- В цикле `for` мы проходим по всем символам в `temp`:
- Сравниваем текущий символ `char` с предыдущим символом `prev`.
- Если они равны, увеличиваем счетчик `cnt`.
- Если они не равны, то добавляем в `ans` количество повторений `cnt` и предыдущий символ `prev`. Затем устанавливаем `prev` равным текущему символу и сбрасываем `cnt` в 1.
- После обработки всех символов в `temp` мы добавляем в `ans` окончательное количество повторений `cnt` и последний символ из `temp`.
5. Обновление строк:
- После генерации новой строки в `ans` мы присваиваем ее значение переменной `temp` для дальнейшего использования.
- Сбрасываем `ans` в пустую строку, чтобы можно было использовать ее для генерации следующей строки.
6. Возврат результата:
- После завершения циклов `temp` содержит `n`-ю строку последовательности, поэтому мы ее возвращаем.
Условие:
Последовательность count-and-say - это последовательность цифровых строк, определяемая рекурсивной формулой:
count-And-Say(1) = "1"
countAndSay(n) - это кодировка длины цикла countAndSay(n - 1).
Кодирование по длине строки (RLE) - это метод сжатия строк, который работает путем замены последовательных идентичных символов (повторяющихся 2 или более раз) путем объединения символа и числа, обозначающего количество символов (длину строки). Например, чтобы сжать строку "3322251", мы заменяем "33" на "23", заменяем "222" на "32", заменяем "5" на "15" и заменяем "1" на "11". Таким образом, сжатая строка становится "23321511".
Учитывая положительное целое число n, верните n-й элемент последовательности подсчета и произнесения.
Решение:
class Solution {
countAndSay(n) {
if (n === 1) {
return "1"; // Base case
}
let ans = "";
let temp = "1";
for (let i = 2; i <= n; i++) {
let cnt = 0;
let prev = temp[0];
for (let j = 0; j < temp.length; j++) {
const char = temp[j];
if (prev === char) {
cnt++; // brute force
} else {
ans += cnt.toString(); // adding count to the end
ans += temp[j - 1];
prev = char;
cnt = 1;
}
}
ans += cnt.toString();
ans += temp[temp.length - 1];
temp = ans; // assigning ans to temp and making ans = ""
ans = ""; // so that we can iterate over temp again!
}
return temp;
}
}Пояснение:
1. Базовый случай:
- Если `n` равен 1, то функция возвращает "1" - это первая строка последовательности.
2. Инициализация:
- `ans` - строка, которая будет хранить результат генерации следующей строки.
- `temp` - строка, которая хранит предыдущую строку. Изначально она равна "1".
3. Цикл для генерации строк:
- Цикл `for` выполняется `n-1` раз, чтобы сгенерировать строки с 2-й по `n`-ю.
- Внутри цикла:
- `cnt` - счетчик, который хранит количество повторений текущего символа.
- `prev` - предыдущий символ, который мы обрабатываем.
4. Генерация следующей строки:
- В цикле `for` мы проходим по всем символам в `temp`:
- Сравниваем текущий символ `char` с предыдущим символом `prev`.
- Если они равны, увеличиваем счетчик `cnt`.
- Если они не равны, то добавляем в `ans` количество повторений `cnt` и предыдущий символ `prev`. Затем устанавливаем `prev` равным текущему символу и сбрасываем `cnt` в 1.
- После обработки всех символов в `temp` мы добавляем в `ans` окончательное количество повторений `cnt` и последний символ из `temp`.
5. Обновление строк:
- После генерации новой строки в `ans` мы присваиваем ее значение переменной `temp` для дальнейшего использования.
- Сбрасываем `ans` в пустую строку, чтобы можно было использовать ее для генерации следующей строки.
6. Возврат результата:
- После завершения циклов `temp` содержит `n`-ю строку последовательности, поэтому мы ее возвращаем.
👍3❤1
Задача: 39. Combination Sum #medium
Условие:
Решение:
Пояснение:
Данный код реализует функцию combinationSum для поиска всех уникальных комбинаций чисел из массива candidates, которые в сумме дают целевое число target. Вот краткое объяснение кода:
1. Использование рекурсивной функции:
- Функция sum_rec - это рекурсивная функция, которая принимает текущую пробу curr_trial (текущую комбинацию чисел), текущую сумму curr_sum (сумму чисел в текущей комбинации), и индекс start_idx (индекс, с которого начинать итерацию по массиву candidates).
2. Проход по массиву candidates:
- Цикл for проходит по элементам массива candidates, начиная с индекса start_idx.
- Для каждого элемента массива c = candidates[i]:
- Увеличивается текущая сумма curr_sum на значение c.
- Элемент c добавляется в текущую пробу curr_trial.
- Если curr_sum меньше целевого значения target, вызывается рекурсивная функция sum_rec для продолжения поиска комбинаций.
- Если curr_sum равна целевому значению target, текущая комбинация добавляется в массив решений sols.
3. Удаление элемента и возврат:
- После завершения итерации по элементам, элемент c удаляется из текущей пробы curr_trial, и его значение вычитается из текущей суммы curr_sum.
- Функция возвращает массив sols, содержащий все найденные комбинации чисел, дающие целевую сумму target.
Этот код эффективно использует рекурсию для поиска всех возможных комбинаций чисел из массива candidates, которые в сумме дают целевое число target. Каждая найденная комбинация добавляется в массив решений sols.
Условие:
При наличии массива различных целых чисел-кандидатов и целевого целевого числа target возвращает список всех уникальных комбинаций кандидатов, в которых выбранные числа суммируются с target. Вы можете возвращать комбинации в любом порядке.
Одно и то же число может быть выбрано из кандидатов неограниченное количество раз. Две комбинации считаются уникальными, если частота, по крайней мере, одного из выбранных чисел различна.
Тестовые примеры генерируются таким образом, чтобы количество уникальных комбинаций, которые в сумме дают целевое значение, составляло менее 150 комбинаций для заданных входных данных.
Решение:
/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum = function(candidates, target) {
let sols = [];
let sum_rec = (curr_trial, curr_sum, start_idx) => {
for (let i = start_idx; i < candidates.length; i++) {
const c = candidates[i];
curr_sum += c;
curr_trial.push(c);
if (curr_sum < target) {
sum_rec(curr_trial, curr_sum, i);
} else if (curr_sum === target) {
sols.push(JSON.parse(JSON.stringify(curr_trial)));
}
curr_sum -= c;
curr_trial.pop();
}
}
sum_rec([], 0, 0);
return sols;
};
Пояснение:
Данный код реализует функцию combinationSum для поиска всех уникальных комбинаций чисел из массива candidates, которые в сумме дают целевое число target. Вот краткое объяснение кода:
1. Использование рекурсивной функции:
- Функция sum_rec - это рекурсивная функция, которая принимает текущую пробу curr_trial (текущую комбинацию чисел), текущую сумму curr_sum (сумму чисел в текущей комбинации), и индекс start_idx (индекс, с которого начинать итерацию по массиву candidates).
2. Проход по массиву candidates:
- Цикл for проходит по элементам массива candidates, начиная с индекса start_idx.
- Для каждого элемента массива c = candidates[i]:
- Увеличивается текущая сумма curr_sum на значение c.
- Элемент c добавляется в текущую пробу curr_trial.
- Если curr_sum меньше целевого значения target, вызывается рекурсивная функция sum_rec для продолжения поиска комбинаций.
- Если curr_sum равна целевому значению target, текущая комбинация добавляется в массив решений sols.
3. Удаление элемента и возврат:
- После завершения итерации по элементам, элемент c удаляется из текущей пробы curr_trial, и его значение вычитается из текущей суммы curr_sum.
- Функция возвращает массив sols, содержащий все найденные комбинации чисел, дающие целевую сумму target.
Этот код эффективно использует рекурсию для поиска всех возможных комбинаций чисел из массива candidates, которые в сумме дают целевое число target. Каждая найденная комбинация добавляется в массив решений sols.
❤1
Задача: 40. Combination Sum ll #medium
Условие:
Решение:
Пояснение:
Данный код реализует функцию combinationSum2 для поиска уникальных комбинаций чисел из массива candidates, которые в сумме дают целевое число target. В отличие от функции combinationSum, данная функция также учитывает, что каждый элемент из массива candidates может использоваться только один раз в каждой комбинации. Вот краткое объяснение кода:
1. Инициализация переменных:
- Создается пустой массив res для хранения найденных комбинаций, пустой массив track для временного хранения текущей комбинации чисел, и переменная trackSum для отслеживания суммы чисел в текущей комбинации.
2. Функция backtrack:
- Функция backtrack рекурсивно итерирует по массиву nums начиная с индекса start.
- На каждом шаге проверяется, достигнута ли целевая сумма target. Если да, то текущая комбинация добавляется в массив решений res.
- Если текущая сумма trackSum становится больше целевой суммы target, то рекурсия завершается для данной ветви.
- При итерации по массиву nums, пропускаются дубликаты элементов, чтобы избежать повторных комбинаций.
- Для каждого числа nums[i]: добавляется в текущую комбинацию track, увеличивается trackSum, вызывается рекурсия для следующего элемента, после чего число удаляется из текущей комбинации и value trackSum уменьшается.
3. Сортировка и вызов рекурсии:
- Массив candidates сортируется в порядке возрастания.
- Затем вызывается функция backtrack, начиная с отсортированного массива candidates.
- В конце возвращается массив res, содержащий все уникальные комбинации чисел, дающие целевую сумму target без повторений элементов.
Этот код использует метод возврата к трассировке (backtracking) для нахождения всех уникальных комбинаций чисел из массива candidates, дающих сочетание, равное целевой сумме target. Функция учитывает возможные повторяющиеся числа в массиве candidates, исключая их из возможных комбинаций.
Условие:
Учитывая набор номеров-кандидатов (candidates) и целевой номер (target), найдите все уникальные комбинации в кандидатах, где номера-кандидаты суммируются с целевыми.
Каждое число в кандидатах является комбинацией.
может использоваться только один раз в
Примечание: Набор решений не должен содержать повторяющихся комбинаций.
Решение:
var combinationSum2 = function(candidates, target) {
const res = [];
const track = [];
let trackSum = 0;
const backtrack = (nums, start) => {
if(trackSum === target){
res.push(track.slice());
return
}
if(trackSum > target){
return
}
for(let i = start; i < nums.length; i++){
if(i > start && nums[i] === nums[i-1]) continue;
track.push(nums[i]);
trackSum += nums[i];
backtrack(nums, i+1);
track.pop();
trackSum -= nums[i];
}
}
const sorted = candidates.sort((a, b)=>a-b);
backtrack(sorted, 0)
return res
};Пояснение:
Данный код реализует функцию combinationSum2 для поиска уникальных комбинаций чисел из массива candidates, которые в сумме дают целевое число target. В отличие от функции combinationSum, данная функция также учитывает, что каждый элемент из массива candidates может использоваться только один раз в каждой комбинации. Вот краткое объяснение кода:
1. Инициализация переменных:
- Создается пустой массив res для хранения найденных комбинаций, пустой массив track для временного хранения текущей комбинации чисел, и переменная trackSum для отслеживания суммы чисел в текущей комбинации.
2. Функция backtrack:
- Функция backtrack рекурсивно итерирует по массиву nums начиная с индекса start.
- На каждом шаге проверяется, достигнута ли целевая сумма target. Если да, то текущая комбинация добавляется в массив решений res.
- Если текущая сумма trackSum становится больше целевой суммы target, то рекурсия завершается для данной ветви.
- При итерации по массиву nums, пропускаются дубликаты элементов, чтобы избежать повторных комбинаций.
- Для каждого числа nums[i]: добавляется в текущую комбинацию track, увеличивается trackSum, вызывается рекурсия для следующего элемента, после чего число удаляется из текущей комбинации и value trackSum уменьшается.
3. Сортировка и вызов рекурсии:
- Массив candidates сортируется в порядке возрастания.
- Затем вызывается функция backtrack, начиная с отсортированного массива candidates.
- В конце возвращается массив res, содержащий все уникальные комбинации чисел, дающие целевую сумму target без повторений элементов.
Этот код использует метод возврата к трассировке (backtracking) для нахождения всех уникальных комбинаций чисел из массива candidates, дающих сочетание, равное целевой сумме target. Функция учитывает возможные повторяющиеся числа в массиве candidates, исключая их из возможных комбинаций.
👍2❤1
Задача: 41. First Missing Positive #hard
Условие:
Решение:
Пояснение:
Данный код представляет собой решение задачи нахождения наименьшего положительного целого числа, которого нет в массиве чисел nums. Давай разберем детальное пояснение к каждой части кода:
1. Инициализация переменных:
- Создается переменная n, которая хранит длину массива nums.
- Создается переменная n1, которая равна n + 1. Она будет использоваться для обозначения отсутствующего значения.
2. Обработка отрицательных чисел и чисел, превышающих длину массива:
- В цикле for перебираются все элементы массива nums.
- Если текущий элемент nums[i] меньше или равен 0 или больше длины массива n, то он заменяется на значение n1, чтобы исключить отрицательные числа и числа, превышающие длину массива.
3. Обработка и пометка чисел:
- Далее выполняется цикл for...of по массиву nums.
- Для каждого числа num выполняются следующие действия:
- Вычисляется индекс i как модуль числа num - 1.
- Если индекс i меньше n и значение nums[i] больше 0, то значение nums[i] умножается на -1. Это помечает, что число i+1 присутствует в массиве nums.
4. Поиск недостающего числа:
- Затем выполняется третий цикл for, который проверяет массив nums на наличие первого положительного числа.
- Если такое число найдено, функция возвращает его индекс + 1.
5. Возврат значения по умолчанию:
- Если в предыдущем цикле не было найдено положительное число, функция возвращает значение n1, так как все числа от 1 до n уже присутствуют в массиве.
Данный подход позволяет эффективно определить наименьшее положительное целое число, отсутствующее в массиве nums, использовав маркировку и отслеживание присутствия чисел в массиве.
Условие:
Задан несортированный целочисленный массив nums. Возвращает наименьшее положительное целое число, которого нет в nums.
Необходимо реализовать алгоритм, который выполняется за 0(n) времени и использует 0(1) вспомогательного пространства.
Решение:
/**
* @param {number[]} nums
* @return {number}
*/
var firstMissingPositive = function(nums) {
const n = nums.length
const n1 = n + 1
for (let i = 0; i < n; i++)
if (nums[i] <= 0 || nums[i] > n)
nums[i] = n1
for (let num of nums) {
i = Math.abs(num) - 1
if (i < n && nums[i] > 0)
nums[i] *= -1
}
for (let i = 0; i < n; i++)
if (nums[i] > 0)
return i + 1
return n1
};
Пояснение:
Данный код представляет собой решение задачи нахождения наименьшего положительного целого числа, которого нет в массиве чисел nums. Давай разберем детальное пояснение к каждой части кода:
1. Инициализация переменных:
- Создается переменная n, которая хранит длину массива nums.
- Создается переменная n1, которая равна n + 1. Она будет использоваться для обозначения отсутствующего значения.
2. Обработка отрицательных чисел и чисел, превышающих длину массива:
- В цикле for перебираются все элементы массива nums.
- Если текущий элемент nums[i] меньше или равен 0 или больше длины массива n, то он заменяется на значение n1, чтобы исключить отрицательные числа и числа, превышающие длину массива.
3. Обработка и пометка чисел:
- Далее выполняется цикл for...of по массиву nums.
- Для каждого числа num выполняются следующие действия:
- Вычисляется индекс i как модуль числа num - 1.
- Если индекс i меньше n и значение nums[i] больше 0, то значение nums[i] умножается на -1. Это помечает, что число i+1 присутствует в массиве nums.
4. Поиск недостающего числа:
- Затем выполняется третий цикл for, который проверяет массив nums на наличие первого положительного числа.
- Если такое число найдено, функция возвращает его индекс + 1.
5. Возврат значения по умолчанию:
- Если в предыдущем цикле не было найдено положительное число, функция возвращает значение n1, так как все числа от 1 до n уже присутствуют в массиве.
Данный подход позволяет эффективно определить наименьшее положительное целое число, отсутствующее в массиве nums, использовав маркировку и отслеживание присутствия чисел в массиве.