Задача: 537. Complex Number Multiplication
Сложность: medium
Комплексное число можно представить в виде строки в формате "real+imaginaryi", где:
real — это действительная часть и является целым числом в диапазоне [-100, 100].
imaginary — это мнимая часть и является целым числом в диапазоне [-100, 100].
i^2 == -1.
Даны два комплексных числа num1 и num2 в виде строк, верните строку комплексного числа, представляющую их произведение.
Пример:
👨💻 Алгоритм:
1⃣ Извлечение реальной и мнимой частей:
Разделите строки a и b на реальные и мнимые части, используя символы '+' и 'i'.
2⃣ Вычисление произведения:
Переведите извлечённые части в целые числа.
Используйте формулу для умножения комплексных чисел: (a+ib)×(x+iy)=ax−by+i(bx+ay).
3⃣ Формирование строки результата:
Создайте строку в требуемом формате с реальной и мнимой частями произведения и верните её.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Комплексное число можно представить в виде строки в формате "real+imaginaryi", где:
real — это действительная часть и является целым числом в диапазоне [-100, 100].
imaginary — это мнимая часть и является целым числом в диапазоне [-100, 100].
i^2 == -1.
Даны два комплексных числа num1 и num2 в виде строк, верните строку комплексного числа, представляющую их произведение.
Пример:
Input: num1 = "1+1i", num2 = "1+1i"
Output: "0+2i"
Explanation: (1 + i) * (1 + i) = 1 + i2 + 2 * i = 2i, and you need convert it to the form of 0+2i.
Разделите строки a и b на реальные и мнимые части, используя символы '+' и 'i'.
Переведите извлечённые части в целые числа.
Используйте формулу для умножения комплексных чисел: (a+ib)×(x+iy)=ax−by+i(bx+ay).
Создайте строку в требуемом формате с реальной и мнимой частями произведения и верните её.
class Solution {
fun complexNumberMultiply(a: String, b: String): String {
val x = a.split("+", "i")
val y = b.split("+", "i")
val a_real = x[0].toInt()
val a_img = x[1].toInt()
val b_real = y[0].toInt()
val b_img = y[1].toInt()
val realPart = a_real * b_real - a_img * b_img
val imaginaryPart = a_real * b_img + a_img * b_real
return "$realPart+$imaginaryPart" + "i"
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1000. Minimum Cost to Merge Stones
Сложность: hard
Имеется n кучек камней, расположенных в ряд. В i-й куче находятся камни stones[i]. Ход состоит в объединении ровно k последовательных куч в одну кучу, и стоимость этого хода равна общему количеству камней в этих k кучах. Верните минимальную стоимость объединения всех куч камней в одну кучу. Если это невозможно, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Проверка на возможность объединения:
Проверьте, можно ли объединить все кучи в одну, если количество куч n не равно 1 по модулю k-1. Если нет, верните -1.
2⃣ Инициализация и динамическое программирование:
Создайте таблицу dp для хранения минимальных затрат на объединение подмассивов камней.
Используйте таблицу prefix для хранения префиксных сумм камней, чтобы быстро вычислять сумму камней в подмассиве.
3⃣ Заполнение таблицы dp:
Заполните таблицу dp минимальными затратами на объединение подмассивов камней, используя динамическое программирование.
Для каждого подмассива длиной от k до n, найдите минимальную стоимость его объединения.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Имеется n кучек камней, расположенных в ряд. В i-й куче находятся камни stones[i]. Ход состоит в объединении ровно k последовательных куч в одну кучу, и стоимость этого хода равна общему количеству камней в этих k кучах. Верните минимальную стоимость объединения всех куч камней в одну кучу. Если это невозможно, верните -1.
Пример:
Input: stones = [3,2,4,1], k = 2
Output: 20
Проверьте, можно ли объединить все кучи в одну, если количество куч n не равно 1 по модулю k-1. Если нет, верните -1.
Создайте таблицу dp для хранения минимальных затрат на объединение подмассивов камней.
Используйте таблицу prefix для хранения префиксных сумм камней, чтобы быстро вычислять сумму камней в подмассиве.
Заполните таблицу dp минимальными затратами на объединение подмассивов камней, используя динамическое программирование.
Для каждого подмассива длиной от k до n, найдите минимальную стоимость его объединения.
class Solution {
fun mergeStones(stones: IntArray, k: Int): Int {
val n = stones.size
if ((n - 1) % (k - 1) != 0) return -1
val prefix = IntArray(n + 1)
for (i in stones.indices) {
prefix[i + 1] = prefix[i] + stones[i]
}
val dp = Array(n) { IntArray(n) }
for (m in k..n) {
for (i in 0..n - m) {
val j = i + m - 1
dp[i][j] = Int.MAX_VALUE
for (t in i until j step k - 1) {
dp[i][j] = minOf(dp[i][j], dp[i][t] + dp[t + 1][j])
}
if ((j - i) % (k - 1) == 0) {
dp[i][j] += prefix[j + 1] - prefix[i]
}
}
}
return dp[0][n - 1]
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1216. Valid Palindrome III
Сложность: hard
Дана строка s и целое число k. Верните true, если s является k-палиндромом.
Строка является k-палиндромом, если её можно преобразовать в палиндром, удалив из неё не более k символов.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте двухмерный массив memo для хранения промежуточных результатов, чтобы избежать повторных вычислений. Определите функцию isValidPalindrome, которая будет возвращать минимальное количество удалений для создания палиндрома в подстроке от индекса i до j.
2⃣ Реализуйте базовые случаи для функции isValidPalindrome: если i равно j, то это уже палиндром, если i и j - соседние индексы, то возвращается 1, если символы не совпадают. Если значение для пары индексов уже рассчитано, то возвращается сохраненное значение из memo.
3⃣ Реализуйте основные случаи рекурсивного вычисления: если символы на позициях i и j совпадают, продолжайте проверку для подстроки без этих символов. В противном случае, рассмотрите два варианта удаления символов и выберите минимальное количество удалений, добавив 1 за текущее удаление.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана строка s и целое число k. Верните true, если s является k-палиндромом.
Строка является k-палиндромом, если её можно преобразовать в палиндром, удалив из неё не более k символов.
Пример:
Input: s = "abcdeca", k = 2
Output: true
Explanation: Remove 'b' and 'e' characters.
class Solution {
private lateinit var memo: Array<IntArray?>
fun isValidPalindrome(s: String, k: Int): Boolean {
val n = s.length
memo = Array(n) { IntArray(n) { -1 } }
return isValidPalindromeHelper(s.toCharArray(), 0, n - 1) <= k
}
private fun isValidPalindromeHelper(s: CharArray, i: Int, j: Int): Int {
if (i == j) return 0
if (i == j - 1) return if (s[i] != s[j]) 1 else 0
if (memo[i][j] != -1) return memo[i][j]
memo[i][j] = if (s[i] == s[j]) {
isValidPalindromeHelper(s, i + 1, j - 1)
} else {
1 + minOf(isValidPalindromeHelper(s, i + 1, j), isValidPalindromeHelper(s, i, j - 1))
}
return memo[i][j]
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1208. Get Equal Substrings Within Budget
Сложность: medium
Вам даны две строки s и t одинаковой длины и целое число maxCost.
Вы хотите преобразовать s в t. Изменение i-го символа строки s на i-й символ строки t стоит |s[i] - t[i]| (т.е. абсолютная разница между значениями ASCII символов).
Верните максимальную длину подстроки s, которую можно изменить, чтобы она соответствовала соответствующей подстроке t с затратами, не превышающими maxCost. Если нет подстроки из s, которую можно изменить на соответствующую подстроку из t, верните 0.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
maxLen для хранения максимальной длины подстроки с затратами, не превышающими maxCost.
start для хранения начального индекса текущей подстроки.
currCost для хранения текущих затрат на преобразование подстроки s в t.
2⃣ Итерация по индексам от 0 до N-1:
Добавить текущие затраты на преобразование символа s[i] в t[i] к currCost.
Удалять элементы с левого конца, уменьшая затраты до тех пор, пока currCost не станет меньше или равным maxCost.
Обновить maxLen длиной текущей подстроки.
3⃣ Возврат maxLen как результата.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам даны две строки s и t одинаковой длины и целое число maxCost.
Вы хотите преобразовать s в t. Изменение i-го символа строки s на i-й символ строки t стоит |s[i] - t[i]| (т.е. абсолютная разница между значениями ASCII символов).
Верните максимальную длину подстроки s, которую можно изменить, чтобы она соответствовала соответствующей подстроке t с затратами, не превышающими maxCost. Если нет подстроки из s, которую можно изменить на соответствующую подстроку из t, верните 0.
Пример:
Input: s = "abcd", t = "bcdf", maxCost = 3
Output: 3
Explanation: "abc" of s can change to "bcd".
That costs 3, so the maximum length is 3.
maxLen для хранения максимальной длины подстроки с затратами, не превышающими maxCost.
start для хранения начального индекса текущей подстроки.
currCost для хранения текущих затрат на преобразование подстроки s в t.
Добавить текущие затраты на преобразование символа s[i] в t[i] к currCost.
Удалять элементы с левого конца, уменьшая затраты до тех пор, пока currCost не станет меньше или равным maxCost.
Обновить maxLen длиной текущей подстроки.
class Solution {
fun equalSubstring(s: String, t: String, maxCost: Int): Int {
val N = s.length
var maxLen = 0
var start = 0
var currCost = 0
for (i in 0 until N) {
currCost += kotlin.math.abs(s[i] - t[i])
while (currCost > maxCost) {
currCost -= kotlin.math.abs(s[start] - t[start])
start++
}
maxLen = maxOf(maxLen, i - start + 1)
}
return maxLen
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 663. Equal Tree Partition
Сложность: medium
Дан корень бинарного дерева. Верните true, если можно разделить дерево на два дерева с равными суммами значений после удаления ровно одного ребра из исходного дерева.
Пример:
👨💻 Алгоритм:
1⃣ Вычисление общей суммы:
Напишите функцию для вычисления общей суммы всех узлов дерева.
2⃣ Проверка возможности разделения:
Напишите функцию, чтобы рекурсивно проверить, может ли поддерево быть равно половине общей суммы. Если такое поддерево найдено, значит дерево можно разделить на две части с равными суммами.
3⃣ Валидация и возврат результата:
Проверьте, что общая сумма четная (так как только в этом случае возможно её разделение на две равные части), и используйте функцию проверки поддерева, чтобы определить, можно ли разделить дерево на две части с равными суммами.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева. Верните true, если можно разделить дерево на два дерева с равными суммами значений после удаления ровно одного ребра из исходного дерева.
Пример:
Input: root = [5,10,10,null,null,2,3]
Output: true
Напишите функцию для вычисления общей суммы всех узлов дерева.
Напишите функцию, чтобы рекурсивно проверить, может ли поддерево быть равно половине общей суммы. Если такое поддерево найдено, значит дерево можно разделить на две части с равными суммами.
Проверьте, что общая сумма четная (так как только в этом случае возможно её разделение на две равные части), и используйте функцию проверки поддерева, чтобы определить, можно ли разделить дерево на две части с равными суммами.
class TreeNode(var `val`: Int) {
var left: TreeNode? = null
var right: TreeNode? = null
}
class Solution {
fun checkEqualTree(root: TreeNode?): Boolean {
if (root == null) return false
val totalSum = sumTree(root)
if (totalSum % 2 != 0) return false
val target = totalSum / 2
return checkSubtreeSum(root, target, root)
}
private fun sumTree(node: TreeNode?): Int {
if (node == null) return 0
return node.`val` + sumTree(node.left) + sumTree(node.right)
}
private fun checkSubtreeSum(node: TreeNode?, target: Int, root: TreeNode): Boolean {
if (node == null) return false
if (node !== root && sumTree(node) == target) {
return true
}
return checkSubtreeSum(node.left, target, root) || checkSubtreeSum(node.right, target, root)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 39. Combination Sum
Сложность: medium
Дан массив
Верните все уникальные комбинации, сумма которых равна
Одно число можно использовать неограниченное количество раз.
Пример:
👨💻 Алгоритм:
1⃣ Используем
2⃣ Если
3⃣ Если
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив
candidates уникальных целых чисел и целевое число target. Верните все уникальные комбинации, сумма которых равна
target. Одно число можно использовать неограниченное количество раз.
Пример:
Input: candidates = [2,3,5], target = 8
Output: [[2,2,2,2],[2,3,3],[3,5]]
backtracking, начиная с пустой комбинации и target. target == 0, добавляем комбинацию в результат. target < 0, отменяем текущий путь, иначе продолжаем рекурсию, начиная с текущего индекса. class Solution {
fun combinationSum(candidates: IntArray, target: Int): List<List<Int>> {
val results = mutableListOf<List<Int>>()
fun backtrack(remain: Int, comb: MutableList<Int>, start: Int) {
when {
remain == 0 -> results.add(ArrayList(comb))
remain > 0 -> {
for (i in start until candidates.size) {
comb.add(candidates[i])
backtrack(remain - candidates[i], comb, i)
comb.removeAt(comb.size - 1)
}
}
}
}
backtrack(target, mutableListOf(), 0)
return results
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 927. Three Equal Parts
Сложность: hard
Вам дан массив arr, состоящий только из нулей и единиц. Разделите массив на три непустые части так, чтобы все эти части представляли одно и то же двоичное значение. Если это возможно, верните любой [i, j] с i + 1 < j, такой что: arr[0], arr[1], ..., arr[i] - это первая часть, arr[i + 1], arr[i + 2], ...., arr[j - 1] - вторая часть, и arr[j], arr[j + 1], ..., arr[arr.length - 1] - третья часть. Все три части имеют одинаковые двоичные значения. Если это невозможно, верните [-1, -1]. Обратите внимание, что вся часть используется при рассмотрении того, какое двоичное значение она представляет. Например, [1,1,0] представляет 6 в десятичной системе, а не 3. Кроме того, допускаются ведущие нули, поэтому [0,1,1] и [1,1] представляют одно и то же значение.
Пример:
👨💻 Алгоритм:
1⃣ Подсчитать количество единиц в массиве.
2⃣ Если количество единиц не делится на три, вернуть [-1, -1].
Найти индексы начала каждой части, игнорируя ведущие нули.
Использовать эти индексы для проверки, могут ли три части быть одинаковыми.
3⃣ Если три части одинаковы, вернуть соответствующие индексы, иначе вернуть [-1, -1].
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Вам дан массив arr, состоящий только из нулей и единиц. Разделите массив на три непустые части так, чтобы все эти части представляли одно и то же двоичное значение. Если это возможно, верните любой [i, j] с i + 1 < j, такой что: arr[0], arr[1], ..., arr[i] - это первая часть, arr[i + 1], arr[i + 2], ...., arr[j - 1] - вторая часть, и arr[j], arr[j + 1], ..., arr[arr.length - 1] - третья часть. Все три части имеют одинаковые двоичные значения. Если это невозможно, верните [-1, -1]. Обратите внимание, что вся часть используется при рассмотрении того, какое двоичное значение она представляет. Например, [1,1,0] представляет 6 в десятичной системе, а не 3. Кроме того, допускаются ведущие нули, поэтому [0,1,1] и [1,1] представляют одно и то же значение.
Пример:
Input: arr = [1,0,1,0,1]
Output: [0,3]
Найти индексы начала каждой части, игнорируя ведущие нули.
Использовать эти индексы для проверки, могут ли три части быть одинаковыми.
class Solution {
fun threeEqualParts(arr: IntArray): IntArray {
val ones = arr.sum()
if (ones % 3 != 0) return intArrayOf(-1, -1)
if (ones == 0) return intArrayOf(0, arr.size - 1)
val partOnes = ones / 3
var first = 0
var second = 0
var third = 0
var cnt = 0
for (i in arr.indices) {
if (arr[i] == 1) {
when (cnt) {
0 -> first = i
partOnes -> second = i
2 * partOnes -> third = i
}
cnt++
}
}
while (third < arr.size && arr[first] == arr[second] && arr[first] == arr[third]) {
first++
second++
third++
}
return if (third == arr.size) intArrayOf(first - 1, second) else intArrayOf(-1, -1)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 66. Plus One
Сложность: easy
Вам дано большое число, представленное в виде массива целых чисел digits, где каждый элемент digits[i] — это i-я цифра числа. Цифры расположены в порядке от старшей к младшей слева направо. Большое число не содержит ведущих нулей.
Увеличьте большое число на один и верните результирующий массив цифр.
Пример:
👨💻 Алгоритм:
1⃣ Проходим по входному массиву, начиная с конца массива.
2⃣ Устанавливаем все девятки на конце массива в ноль. Если мы встречаем цифру, не равную девяти, увеличиваем её на один. Работа выполнена — возвращаем массив цифр.
3⃣ Мы здесь, потому что все цифры были равны девяти. Теперь они все установлены в ноль. Затем мы добавляем цифру 1 в начало остальных цифр и возвращаем результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дано большое число, представленное в виде массива целых чисел digits, где каждый элемент digits[i] — это i-я цифра числа. Цифры расположены в порядке от старшей к младшей слева направо. Большое число не содержит ведущих нулей.
Увеличьте большое число на один и верните результирующий массив цифр.
Пример:
Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
Incrementing by one gives 123 + 1 = 124.
Thus, the result should be [1,2,4].
class Solution {
fun plusOne(digits: IntArray): IntArray {
val n = digits.size
for (i in n - 1 downTo 0) {
if (digits[i] == 9) {
digits[i] = 0
} else {
digits[i]++
return digits
}
}
val result = IntArray(n + 1)
result[0] = 1
return result
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Задача: 358. Rearrange String k Distance Apart
Сложность: hard
Дана строка s и целое число k, переставьте символы в s так, чтобы одинаковые символы находились на расстоянии не менее k друг от друга. Если невозможно переставить строку, верните пустую строку "".
Пример:
👨💻 Алгоритм:
1⃣ Создайте словарь частот для символов строки и определите максимальную частоту.
2⃣ Разделите символы на группы по частоте и создайте сегменты для размещения символов.
3⃣ Распределите оставшиеся символы по сегментам, проверяя условия, и объедините сегменты в итоговую строку.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана строка s и целое число k, переставьте символы в s так, чтобы одинаковые символы находились на расстоянии не менее k друг от друга. Если невозможно переставить строку, верните пустую строку "".
Пример:
Input: s = "aabbcc", k = 3
Output: "abcabc"
Explanation: The same letters are at least a distance of 3 from each other.
class Solution {
fun rearrangeString(s: String, k: Int): String {
val freqs = mutableMapOf<Char, Int>()
var maxFreq = 0
for (char in s) {
freqs[char] = freqs.getOrDefault(char, 0) + 1
maxFreq = maxOf(maxFreq, freqs[char]!!)
}
val mostChars = freqs.filter { it.value == maxFreq }.keys
val secondChars = freqs.filter { it.value == maxFreq - 1 }.keys
val segments = Array(maxFreq) { StringBuilder() }
for (i in 0 until maxFreq) {
for (char in mostChars) {
segments[i].append(char)
}
if (i < maxFreq - 1) {
for (char in secondChars) {
segments[i].append(char)
}
}
}
var segmentId = 0
for ((char, freq) in freqs) {
if (char in mostChars || char in secondChars) {
continue
}
var freq = freq
while (freq > 0) {
segments[segmentId].append(char)
segmentId = (segmentId + 1) % (maxFreq - 1)
freq--
}
}
for (i in 0 until maxFreq - 1) {
if (segments[i].length < k) {
return ""
}
}
return segments.joinToString("") { it.toString() }
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1481. Least Number of Unique Integers after K Removals
Сложность: medium
Дан массив целых чисел arr и целое число k. Найдите минимальное количество уникальных целых чисел после удаления ровно k элементов.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и построение частотного массива:
Создайте хеш-таблицу для отслеживания частот элементов массива arr.
Итеративно увеличивайте частоту элементов в хеш-таблице.
2⃣ Сортировка и удаление элементов:
Создайте массив частот и заполните его значениями из хеш-таблицы.
Отсортируйте массив частот.
Инициализируйте переменную для отслеживания числа удаленных элементов и итеративно добавляйте частоты, пока количество удаленных элементов не превысит k.
3⃣ Возвращение результата:
Если количество удаленных элементов превысило k, верните оставшееся количество уникальных элементов.
Если все элементы были удалены, верните 0.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел arr и целое число k. Найдите минимальное количество уникальных целых чисел после удаления ровно k элементов.
Пример:
Input: arr = [5,5,4], k = 1
Output: 1
Explanation: Remove the single 4, only 5 is left.
Создайте хеш-таблицу для отслеживания частот элементов массива arr.
Итеративно увеличивайте частоту элементов в хеш-таблице.
Создайте массив частот и заполните его значениями из хеш-таблицы.
Отсортируйте массив частот.
Инициализируйте переменную для отслеживания числа удаленных элементов и итеративно добавляйте частоты, пока количество удаленных элементов не превысит k.
Если количество удаленных элементов превысило k, верните оставшееся количество уникальных элементов.
Если все элементы были удалены, верните 0.
class Solution {
fun findLeastNumOfUniqueInts(arr: IntArray, k: Int): Int {
val freqMap = mutableMapOf<Int, Int>()
for (num in arr) {
freqMap[num] = freqMap.getOrDefault(num, 0) + 1
}
val frequencies = freqMap.values.sorted()
var elementsRemoved = 0
for (i in frequencies.indices) {
elementsRemoved += frequencies[i]
if (elementsRemoved > k) {
return frequencies.size - i
}
}
return 0
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 468. Validate IP Address
Сложность: medium
Допустимый IPv4-адрес — это IP в форме "x1.x2.x3.x4", где 0 <= xi <= 255 и xi не может содержать ведущие нули. Например, "192.168.1.1" и "192.168.1.0" являются допустимыми IPv4-адресами, тогда как "192.168.01.1", "192.168.1.00" и "[email protected]" являются недопустимыми IPv4-адресами.
Допустимый IPv6-адрес — это IP в форме "x1:x2:x3:x4:x5:x6:x7
", где:
1 <= xi.length <= 4
xi — это шестнадцатеричная строка, которая может содержать цифры, строчные английские буквы ('a' до 'f') и прописные английские буквы ('A' до 'F').
Ведущие нули в xi допускаются.
Пример:
👨💻 Алгоритм:
1⃣ Для проверки адреса IPv4:
Разделить IP на четыре части по разделителю ".".
Проверить каждую подстроку:
Является ли она целым числом между 0 и 255.
Не содержит ли она ведущих нулей (исключение — число "0").
2⃣ Для проверки адреса IPv6:
Разделить IP на восемь частей по разделителю ":".
Проверить каждую подстроку:
Является ли она шестнадцатеричным числом длиной от 1 до 4 символов.
3⃣ Если IP не соответствует ни одному из форматов, вернуть "Neither".
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Допустимый IPv4-адрес — это IP в форме "x1.x2.x3.x4", где 0 <= xi <= 255 и xi не может содержать ведущие нули. Например, "192.168.1.1" и "192.168.1.0" являются допустимыми IPv4-адресами, тогда как "192.168.01.1", "192.168.1.00" и "[email protected]" являются недопустимыми IPv4-адресами.
Допустимый IPv6-адрес — это IP в форме "x1:x2:x3:x4:x5:x6:x7
", где:
1 <= xi.length <= 4
xi — это шестнадцатеричная строка, которая может содержать цифры, строчные английские буквы ('a' до 'f') и прописные английские буквы ('A' до 'F').
Ведущие нули в xi допускаются.
Пример:
Input: queryIP = "172.16.254.1"
Output: "IPv4"
Explanation: This is a valid IPv4 address, return "IPv4".
Разделить IP на четыре части по разделителю ".".
Проверить каждую подстроку:
Является ли она целым числом между 0 и 255.
Не содержит ли она ведущих нулей (исключение — число "0").
Разделить IP на восемь частей по разделителю ":".
Проверить каждую подстроку:
Является ли она шестнадцатеричным числом длиной от 1 до 4 символов.
class Solution {
fun validateIPv4(IP: String): String {
val nums = IP.split(".")
for (x in nums) {
if (x.length == 0 || x.length > 3) return "Neither"
if (x[0] == '0' && x.length != 1) return "Neither"
for (ch in x) {
if (!ch.isDigit()) return "Neither"
}
if (x.toInt() > 255) return "Neither"
}
return "IPv4"
}
fun validateIPv6(IP: String): String {
val nums = IP.split(":")
val hexdigits = "0123456789abcdefABCDEF"
for (x in nums) {
if (x.length == 0 || x.length > 4) return "Neither"
for (ch in x) {
if (hexdigits.indexOf(ch) == -1) return "Neither"
}
}
return "IPv6"
}
fun validIPAddress(IP: String): String {
return when {
IP.count { it == '.' } == 3 -> validateIPv4(IP)
IP.count { it == ':' } == 7 -> validateIPv6(IP)
else -> "Neither"
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 957. Prison Cells After N Days
Сложность: medium
Есть 8 тюремных камер в ряду, и каждая камера либо занята, либо пуста.
Каждый день статус камеры, занята она или пуста, меняется по следующим правилам:
Если у камеры два соседних соседа, которые оба заняты или оба пусты, то камера становится занятой.
В противном случае, она становится пустой.
Учтите, что поскольку тюрьма — это ряд, у первой и последней камер в ряду не может быть двух соседних соседей.
Вам дан целочисленный массив cells, где cells[i] == 1, если i-я камера занята, и cells[i] == 0, если i-я камера пуста, и вам дано целое число n.
Верните состояние тюрьмы после n дней (т.е. после n таких изменений, описанных выше).
Пример:
👨💻 Алгоритм:
1⃣ Преобразуйте текущее состояние камер в целое число с помощью битовой маски. Это позволит удобно отслеживать повторяющиеся состояния.
2⃣ Симулируйте изменение состояния камер день за днем, записывая каждое состояние в хэш-таблицу. Если обнаруживается повторяющееся состояние, вычислите длину цикла и уменьшите количество оставшихся дней с учетом этого цикла.
3⃣ Продолжайте симуляцию, пока не достигнете заданного числа дней, либо используйте цикл для ускорения процесса.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Есть 8 тюремных камер в ряду, и каждая камера либо занята, либо пуста.
Каждый день статус камеры, занята она или пуста, меняется по следующим правилам:
Если у камеры два соседних соседа, которые оба заняты или оба пусты, то камера становится занятой.
В противном случае, она становится пустой.
Учтите, что поскольку тюрьма — это ряд, у первой и последней камер в ряду не может быть двух соседних соседей.
Вам дан целочисленный массив cells, где cells[i] == 1, если i-я камера занята, и cells[i] == 0, если i-я камера пуста, и вам дано целое число n.
Верните состояние тюрьмы после n дней (т.е. после n таких изменений, описанных выше).
Пример:
Input: cells = [0,1,0,1,1,0,0,1], n = 7
Output: [0,0,1,1,0,0,0,0]
Explanation: The following table summarizes the state of the prison on each day:
Day 0: [0, 1, 0, 1, 1, 0, 0, 1]
Day 1: [0, 1, 1, 0, 0, 0, 0, 0]
Day 2: [0, 0, 0, 0, 1, 1, 1, 0]
Day 3: [0, 1, 1, 0, 0, 1, 0, 0]
Day 4: [0, 0, 0, 0, 0, 1, 0, 0]
Day 5: [0, 1, 1, 1, 0, 1, 0, 0]
Day 6: [0, 0, 1, 0, 1, 1, 0, 0]
Day 7: [0, 0, 1, 1, 0, 0, 0, 0]
class Solution {
fun cellsToBitmap(cells: IntArray): Int {
var stateBitmap = 0
for (cell in cells) {
stateBitmap = (stateBitmap shl 1) or cell
}
return stateBitmap
}
fun nextDay(cells: IntArray): IntArray {
val newCells = IntArray(cells.size)
for (i in 1 until cells.size - 1) {
newCells[i] = if (cells[i - 1] == cells[i + 1]) 1 else 0
}
return newCells
}
fun prisonAfterNDays(cells: IntArray, N: Int): IntArray {
var cells = cells
var N = N
val seen = mutableMapOf<Int, Int>()
var isFastForwarded = false
while (N > 0) {
if (!isFastForwarded) {
val stateBitmap = cellsToBitmap(cells)
if (stateBitmap in seen) {
N %= seen[stateBitmap]!! - N
isFastForwarded = true
} else {
seen[stateBitmap] = N
}
}
if (N > 0) {
N--
cells = nextDay(cells)
}
}
return cells
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 298. Binary Tree Longest Consecutive Sequence
Сложность: medium
Дан корень бинарного дерева, верните длину самого длинного пути последовательных значений.
Путь последовательных значений — это путь, где значения увеличиваются на единицу вдоль пути.
Обратите внимание, что путь может начинаться с любого узла в дереве, и вы не можете перейти от узла к его родителю на пути.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и начало обхода:
Начните обход дерева с корневого узла.
Инициализируйте переменную length, чтобы хранить текущую длину последовательного пути, и передавайте её вниз по дереву.
2⃣ Сравнение текущего узла с родительским узлом:
Для каждого узла сравните его значение со значением родительского узла.
Если значение текущего узла на единицу больше значения родительского узла, увеличьте length.
Если значение текущего узла не является последовательным (не больше на единицу), сбросьте length на 1.
3⃣ Обход дерева:
Рекурсивно обходите левое и правое поддерево, передавая обновлённое значение length.
В каждом узле обновляйте максимальную длину последовательного пути, если текущая длина больше.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева, верните длину самого длинного пути последовательных значений.
Путь последовательных значений — это путь, где значения увеличиваются на единицу вдоль пути.
Обратите внимание, что путь может начинаться с любого узла в дереве, и вы не можете перейти от узла к его родителю на пути.
Пример:
Input: root = [1,null,3,2,4,null,null,null,5]
Output: 3
Explanation: Longest consecutive sequence path is 3-4-5, so return 3.
Начните обход дерева с корневого узла.
Инициализируйте переменную length, чтобы хранить текущую длину последовательного пути, и передавайте её вниз по дереву.
Для каждого узла сравните его значение со значением родительского узла.
Если значение текущего узла на единицу больше значения родительского узла, увеличьте length.
Если значение текущего узла не является последовательным (не больше на единицу), сбросьте length на 1.
Рекурсивно обходите левое и правое поддерево, передавая обновлённое значение length.
В каждом узле обновляйте максимальную длину последовательного пути, если текущая длина больше.
class Solution {
private var maxLength = 0
fun longestConsecutive(root: TreeNode?): Int {
dfs(root, null, 0)
return maxLength
}
private fun dfs(node: TreeNode?, parent: TreeNode?, length: Int) {
if (node == null) return
var currentLength = length
if (parent != null && node.`val` == parent.`val` + 1) {
currentLength += 1
} else {
currentLength = 1
}
maxLength = maxOf(maxLength, currentLength)
dfs(node.left, node, currentLength)
dfs(node.right, node, currentLength)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 300. Longest Increasing Subsequence
Сложность: medium
Дан массив целых чисел nums, верните длину самой длинной строго возрастающей подпоследовательности.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте массив dp длиной nums.length, все элементы которого равны 1. dp[i] представляет длину самой длинной возрастающей подпоследовательности, которая заканчивается элементом с индексом i.
2⃣ Итерируйтесь от i = 1 до i = nums.length - 1. В каждой итерации используйте второй цикл for для итерации от j = 0 до j = i - 1 (все элементы перед i). Для каждого элемента перед i, проверьте, меньше ли этот элемент, чем nums[i]. Если да, установите dp[i] = max(dp[i], dp[j] + 1).
3⃣ Верните максимальное значение из dp.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums, верните длину самой длинной строго возрастающей подпоследовательности.
Пример:
Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
class Solution {
fun lengthOfLIS(nums: IntArray): Int {
if (nums.isEmpty()) return 0
val dp = IntArray(nums.size) { 1 }
for (i in 1 until nums.size) {
for (j in 0 until i) {
if (nums[i] > nums[j]) {
dp[i] = maxOf(dp[i], dp[j] + 1)
}
}
}
return dp.maxOrNull() ?: 0
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 230. Kth Smallest Element in a BST
Сложность: medium
Дан корень бинарного дерева поиска и целое число k. Верните k-ое по величине значение (нумерация с 1) среди всех значений узлов в дереве.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация стека и обход в глубину: Инициализируйте стек для хранения узлов дерева. Начните обход дерева в глубину, начиная с корня, и перемещайтесь влево, добавляя каждый узел в стек, пока не достигнете самого левого узла.
2⃣ Извлечение узлов и проверка: Когда достигнете самого левого узла, извлеките узел из стека и уменьшите значение k на 1. Если k становится равным нулю, верните значение текущего узла, так как это и есть k-ое по величине значение.
3⃣ Переход к правому поддереву: Если k не равен нулю, переместитесь к правому поддереву текущего узла и продолжайте обход, повторяя шаги 1 и 2, пока не найдете k-ое по величине значение.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева поиска и целое число k. Верните k-ое по величине значение (нумерация с 1) среди всех значений узлов в дереве.
Пример:
Input: root = [3,1,4,null,2], k = 1
Output: 1
class Solution {
fun kthSmallest(root: TreeNode?, k: Int): Int {
val stack = LinkedList<TreeNode>()
var root = root
var k = k
while (true) {
while (root != null) {
stack.push(root)
root = root.left
}
root = stack.pop()
if (--k == 0) return root.`val`
root = root.right
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 675. Cut Off Trees for Golf Event
Сложность: hard
Вам необходимо срубить все деревья в лесу для проведения гольф-мероприятия. Лес представлен в виде матрицы m x n. В этой матрице:
- 0 означает, что ячейка непроходима.
- 1 представляет собой пустую проходимую ячейку.
- Число больше 1 представляет собой дерево в ячейке, и это число обозначает высоту дерева.
За один шаг вы можете передвигаться в любом из четырех направлений: север, восток, юг и запад. Если вы стоите в ячейке с деревом, вы можете выбрать, срубить его или нет.
Вы должны срубить деревья в порядке от самого низкого до самого высокого. Когда вы срубаете дерево, значение в его ячейке становится 1 (пустая ячейка).
Начиная с точки (0, 0), верните минимальное количество шагов, необходимых для того, чтобы срубить все деревья. Если невозможно срубить все деревья, верните -1.
Примечание: Входные данные сформированы так, что нет двух деревьев с одинаковой высотой, и нужно срубить как минимум одно дерево.
Пример:
👨💻 Алгоритм:
1⃣ Начиная с (0, 0), для каждого дерева в порядке возрастания высоты будем вычислять расстояние от текущего местоположения до следующего дерева (и перемещаться туда), добавляя это расстояние к ответу.
2⃣ Формулируем задачу как предоставление функции расстояния dist(forest, sr, sc, tr, tc), которая вычисляет расстояние от точки (sr, sc) до цели (tr, tc) с учетом препятствий, где dist[i][j] == 0. (Эта функция расстояния вернет -1, если путь невозможен.)
3⃣ Далее следует код и анализ сложности, которые общие для всех трех подходов. Затем алгоритмы, представленные в наших подходах, будут сосредоточены только на предоставлении нашей функции dist.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Вам необходимо срубить все деревья в лесу для проведения гольф-мероприятия. Лес представлен в виде матрицы m x n. В этой матрице:
- 0 означает, что ячейка непроходима.
- 1 представляет собой пустую проходимую ячейку.
- Число больше 1 представляет собой дерево в ячейке, и это число обозначает высоту дерева.
За один шаг вы можете передвигаться в любом из четырех направлений: север, восток, юг и запад. Если вы стоите в ячейке с деревом, вы можете выбрать, срубить его или нет.
Вы должны срубить деревья в порядке от самого низкого до самого высокого. Когда вы срубаете дерево, значение в его ячейке становится 1 (пустая ячейка).
Начиная с точки (0, 0), верните минимальное количество шагов, необходимых для того, чтобы срубить все деревья. Если невозможно срубить все деревья, верните -1.
Примечание: Входные данные сформированы так, что нет двух деревьев с одинаковой высотой, и нужно срубить как минимум одно дерево.
Пример:
Input: forest = [[1,2,3],[0,0,4],[7,6,5]]
Output: 6
Explanation: Following the path above allows you to cut off the trees from shortest to tallest in 6 steps.
class Solution {
fun cutOffTree(forest: List<List<Int>>): Int {
val trees = forest.withIndex().flatMap { (r, row) ->
row.withIndex().mapNotNull { (c, v) ->
if (v > 1) Triple(v, r, c) else null
}
}.sortedBy { it.first }
var sr = 0
var sc = 0
var ans = 0
for ((_, tr, tc) in trees) {
val d = dist(forest, sr, sc, tr, tc)
if (d < 0) return -1
ans += d
sr = tr
sc = tc
}
return ans
}
fun dist(forest: List<List<Int>>, sr: Int, sc: Int, tr: Int, tc: Int): Int {
// Implement the distance function here
return 0
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 253. Meeting Rooms II
Сложность: medium
Дан массив интервалов времени встреч intervals, где intervals[i] = [starti, endi]. Верните минимальное количество необходимых конференц-залов.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте встречи по времени их начала и инициализируйте мин-кучу с временем окончания первой встречи.
2⃣ Для каждой последующей встречи проверьте, свободна ли комната (сравните время начала встречи с минимальным временем окончания в куче):
Если свободна, обновите время окончания этой комнаты.
Если не свободна, добавьте новое время окончания в кучу.
3⃣ После обработки всех встреч размер кучи будет равен минимальному количеству необходимых комнат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив интервалов времени встреч intervals, где intervals[i] = [starti, endi]. Верните минимальное количество необходимых конференц-залов.
Пример:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: 2
Если свободна, обновите время окончания этой комнаты.
Если не свободна, добавьте новое время окончания в кучу.
import java.util.*
class Solution {
fun minMeetingRooms(intervals: Array<IntArray>): Int {
intervals.sortBy { it[0] }
val heap = PriorityQueue<Int>()
heap.add(intervals[0][1])
for (i in 1 until intervals.size) {
if (intervals[i][0] >= heap.peek()) {
heap.poll()
}
heap.add(intervals[i][1])
}
return heap.size
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1530. Number of Good Leaf Nodes Pairs
Сложность: medium
Вам дан корень бинарного дерева и целое число distance. Пара двух различных листовых узлов бинарного дерева называется хорошей, если длина кратчайшего пути между ними меньше или равна distance.
Верните количество хороших пар листовых узлов в дереве.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте список смежности для преобразования дерева в граф и множество для хранения листовых узлов. Используйте вспомогательный метод traverseTree для обхода дерева, чтобы построить граф и найти листовые узлы. В параметрах поддерживайте текущий узел, а также родительский узел. Если текущий узел является листом, добавьте его в множество. В списке смежности добавьте текущий узел в список соседей родительского узла и наоборот. Рекурсивно вызовите traverseTree для левого и правого дочернего узла текущего узла.
2⃣ Инициализируйте переменную ans для подсчета количества хороших пар листовых узлов. Итеративно переберите каждый листовой узел в множестве. Запустите BFS для текущего листового узла. BFS можно прервать досрочно, как только будут обнаружены все узлы, находящиеся на расстоянии от текущего листового узла. Увеличьте ans для каждого листового узла, найденного в каждом запуске BFS.
3⃣ Верните ans / 2. Мы считаем каждую пару дважды, поэтому нужно разделить на 2, чтобы получить фактическое количество.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан корень бинарного дерева и целое число distance. Пара двух различных листовых узлов бинарного дерева называется хорошей, если длина кратчайшего пути между ними меньше или равна distance.
Верните количество хороших пар листовых узлов в дереве.
Пример:
Input: root = [1,2,3,null,4], distance = 3
Output: 1
Explanation: The leaf nodes of the tree are 3 and 4 and the length of the shortest path between them is 3. This is the only good pair.
class Solution {
fun countPairs(root: TreeNode?, distance: Int): Int {
val graph = mutableMapOf<TreeNode, MutableList<TreeNode>>()
val leafNodes = mutableSetOf<TreeNode>()
traverseTree(root, null, graph, leafNodes)
var ans = 0
for (leaf in leafNodes) {
val bfsQueue: Queue<TreeNode> = LinkedList()
val seen = mutableSetOf<TreeNode>()
bfsQueue.add(leaf)
seen.add(leaf)
for (i in 0..distance) {
val size = bfsQueue.size
for (j in 0 until size) {
val currNode = bfsQueue.poll()
if (leafNodes.contains(currNode) && currNode != leaf) {
ans++
}
graph[currNode]?.let {
for (neighbor in it) {
if (!seen.contains(neighbor)) {
bfsQueue.add(neighbor)
seen.add(neighbor)
}
}
}
}
}
}
return ans / 2
}
private fun traverseTree(currNode: TreeNode?, prevNode: TreeNode?,
graph: MutableMap<TreeNode, MutableList<TreeNode>>, leafNodes: MutableSet<TreeNode>) {
if (currNode == null) {
return
}
if (currNode.left == null && currNode.right == null) {
leafNodes.add(currNode)
}
if (prevNode != null) {
graph.computeIfAbsent(prevNode) { mutableListOf() }.add(currNode)
graph.computeIfAbsent(currNode) { mutableListOf() }.add(prevNode)
}
traverseTree(currNode.left, currNode, graph, leafNodes)
traverseTree(currNode.right, currNode, graph, leafNodes)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 628. Maximum Product of Three Numbers
Сложность: medium
Задав целочисленный массив nums, найдите три числа, произведение которых максимально, и верните максимальное произведение.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте массив nums.
2⃣ Найдите два возможных максимальных произведения: Произведение трех наибольших элементов массива. Произведение двух наименьших (отрицательных) и одного наибольшего элемента массива.
3⃣ Верните максимальное из двух найденных произведений.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Задав целочисленный массив nums, найдите три числа, произведение которых максимально, и верните максимальное произведение.
Пример:
Input: nums = [1,2,3]
Output: 6
fun maximumProduct(nums: IntArray): Int {
nums.sort()
val n = nums.size
val max1 = nums[n - 1] * nums[n - 2] * nums[n - 3]
val max2 = nums[0] * nums[1] * nums[n - 1]
return kotlin.math.max(max1, max2)
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 259. 3Sum Smaller
Сложность: medium
Дан массив из n целых чисел nums и целое число target. Найдите количество троек индексов i, j, k, удовлетворяющих условию 0 <= i < j < k < n и nums[i] + nums[j] + nums[k] < target.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте массив nums.
2⃣ Для каждого элемента nums[i] от 0 до n-3 найдите количество пар индексов j и k (где i < j < k), таких что nums[i] + nums[j] + nums[k] < target. Используйте функцию twoSumSmaller, которая ищет количество пар с суммой меньше заданного значения.
3⃣ В функции twoSumSmaller используйте бинарный поиск для поиска верхней границы индекса k и подсчета количества подходящих пар.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив из n целых чисел nums и целое число target. Найдите количество троек индексов i, j, k, удовлетворяющих условию 0 <= i < j < k < n и nums[i] + nums[j] + nums[k] < target.
Пример:
Input: nums = [-2,0,1,3], target = 2
Output: 2
Explanation: Because there are two triplets which sums are less than 2:
[-2,0,1]
[-2,0,3]
class Solution {
fun threeSumSmaller(nums: IntArray, target: Int): Int {
nums.sort()
var sum = 0
for (i in 0 until nums.size - 2) {
sum += twoSumSmaller(nums, i + 1, target - nums[i])
}
return sum
}
private fun twoSumSmaller(nums: IntArray, startIndex: Int, target: Int): Int {
var sum = 0
for (i in startIndex until nums.size - 1) {
val j = binarySearch(nums, i, target - nums[i])
sum += j - i
}
return sum
}
private fun binarySearch(nums: IntArray, startIndex: Int, target: Int): Int {
var left = startIndex
var right = nums.size - 1
while (left < right) {
val mid = (leftСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM