ar
Feedback
Kotlin | LeetCode

Kotlin | LeetCode

الذهاب إلى القناة على Telegram
1 737
المشتركون
-124 ساعات
-27 أيام
-930 أيام

جاري تحميل البيانات...

جذب المشتركين
يوليو '26
يوليو '260
في 0 قنوات
يونيو '26
+10
في 0 قنوات
Get PRO
مايو '26
+8
في 0 قنوات
Get PRO
أبريل '26
+9
في 0 قنوات
Get PRO
مارس '26
+18
في 0 قنوات
Get PRO
فبراير '26
+9
في 0 قنوات
Get PRO
يناير '26
+14
في 0 قنوات
Get PRO
ديسمبر '25
+11
في 0 قنوات
Get PRO
نوفمبر '25
+42
في 0 قنوات
Get PRO
أكتوبر '25
+41
في 0 قنوات
Get PRO
سبتمبر '25
+28
في 0 قنوات
Get PRO
أغسطس '25
+43
في 0 قنوات
Get PRO
يوليو '25
+44
في 1 قنوات
Get PRO
يونيو '25
+52
في 0 قنوات
Get PRO
مايو '25
+62
في 0 قنوات
Get PRO
أبريل '25
+57
في 0 قنوات
Get PRO
مارس '25
+93
في 1 قنوات
Get PRO
فبراير '25
+100
في 0 قنوات
Get PRO
يناير '25
+145
في 53 قنوات
Get PRO
ديسمبر '24
+49
في 0 قنوات
Get PRO
نوفمبر '24
+70
في 0 قنوات
Get PRO
أكتوبر '24
+193
في 12 قنوات
Get PRO
سبتمبر '24
+640
في 333 قنوات
Get PRO
أغسطس '24
+90
في 0 قنوات
Get PRO
يوليو '24
+424
في 219 قنوات
Get PRO
يونيو '24
+418
في 232 قنوات
التاريخ
نمو المشتركين
الإشارات
القنوات
01 يوليو0
منشورات القناة
Задача: 863. All Nodes Distance K in Binary Tree Сложность: medium Дан корень бинарного дерева, значение целевого узла target и целое число k. Верните массив значений всех узлов, которые находятся на расстоянии k от целевого узла. Ответ можно вернуть в любом порядке. Пример:
Input: root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, k = 2
Output: [7,4,1]
Explanation: The nodes that are a distance 2 from the target node (with value 5) have values 7, 4, and 1.
👨‍💻 Алгоритм: 1⃣Определите рекурсивную функцию add_parent(cur, parent), чтобы рекурсивно добавлять указатель на родителя к узлу cur. Если cur не пустой, добавьте указатель на parent: cur.parent = parent. Затем рекурсивно вызовите add_parent для левого и правого детей cur: add_parent(cur.left, cur) и add_parent(cur.right, cur). Вызовите add_parent(root, None), чтобы добавить все указатели на родителей (корневой узел не имеет родителя). 2⃣Инициализируйте пустой массив answer и пустое множество visited. Определите рекурсивную функцию dfs(cur, distance) для поиска всех узлов на расстоянии k от узла target. Если cur пустой или уже был посещён, вернитесь. Добавьте cur в visited, чтобы его не посещали повторно. Если distance = k, добавьте cur в answer и вернитесь. 3⃣Рекурсивно вызовите dfs для детей и родителя cur. Вызовите dfs(target, 0), чтобы найти все узлы на расстоянии k. Верните answer после завершения DFS. 😎 Решение:
class Solution {
    fun distanceK(root: TreeNode?, target: TreeNode?, k: Int): List<Int> {
        fun addParent(cur: TreeNode?, parent: TreeNode?) {
            cur?.let {
                it.parent = parent
                addParent(it.left, it)
                addParent(it.right, it)
            }
        }
        addParent(root, null)
        
        val answer = mutableListOf<Int>()
        val visited = mutableSetOf<TreeNode>()
        
        fun dfs(cur: TreeNode?, distance: Int) {
            cur?.let {
                if (it in visited) return
                visited.add(it)
                if (distance == 0) {
                    answer.add(it.`val`)
                    return
                }
                dfs(it.parent, distance - 1)
                dfs(it.left, distance - 1)
                dfs(it.right, distance - 1)
            }
        }
        
        dfs(target, k)
        return answer
    }
}

var TreeNode.parent: TreeNode? by Delegates.observable(null) { _, _, _ -> }
Ставь 👍 и забирай 📚 Базу знаний

2
Задача: 905. Sort Array By Parity Сложность: easy Если задан целочисленный массив nums, переместите все четные числа в начало массива, а затем все нечетные. Верните любой массив, удовлетворяющий этому условию. Пример: Input: nums = [3,1,2,4] Output: [2,4,3,1] 👨‍💻 Алгоритм: 1⃣Создать два списка: один для четных чисел, другой для нечетных. 2⃣Пройтись по массиву и добавить четные числа в один список, а нечетные в другой. 3⃣Объединить два списка и вернуть результат. 😎 Решение: class Solution { fun sortArrayByParity(nums: IntArray): IntArray { val evens = mutableListOf<Int>() val odds = mutableListOf<Int>() for (num in nums) { if (num % 2 == 0) { evens.add(num) } else { odds.add(num) } } evens.addAll(odds) return evens.toIntArray() } } Ставь 👍 и забирай 📚 Базу знаний
108
3
Задача: 903. Valid Permutations for DI Sequence Сложность: hard Вам дана строка s длины n, где s[i] либо: 'D' означает убывание, либо 'I' означает возрастание. Перестановка perm из n + 1 целых чисел всех целых чисел в диапазоне [0, n] называется допустимой, если для всех допустимых i: если s[i] == 'D', то perm[i] > perm[i + 1], а если s[i] == 'I', то perm[i] < perm[i + 1]. Верните количество допустимых перестановок perm. Поскольку ответ может быть большим, верните его по модулю 109 + 7. Пример: Input: s = "DID" Output: 5 👨‍💻 Алгоритм: 1⃣Создать двумерный массив dp, где dp[i][j] представляет количество допустимых перестановок длины i, оканчивающихся на j. 2⃣Заполнить массив dp, учитывая условия возрастания и убывания из строки s. 3⃣Вернуть сумму dp[n][j] для всех j, что даст количество допустимых перестановок длины n + 1. 😎 Решение: class Solution { fun numPermsDISequence(s: String): Int { val MOD = 1_000_000_007 val n = s.length val dp = Array(n + 1) { IntArray(n + 1) } dp[0][0] = 1 for (i in 1..n) { for (j in 0..i) { if (s[i - 1] == 'D') { for (k in j until i) { dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD } } else { for (k in 0 until j) { dp[i][j] = (dp[i][j] + dp[i - 1][k]) % MOD } } } } var result = 0 for (j in 0..n) { result = (result + dp[n][j]) % MOD } return result } } Ставь 👍 и забирай 📚 Базу знаний
97
4
Задача: 673. Number of Longest Increasing Subsequence Сложность: medium Дан массив целых чисел nums, верните количество самых длинных строго возрастающих подпоследовательностей. Пример: Input: n = 1, presses = 1 Output: 2 Explanation: Status can be: - [off] by pressing button 1 - [on] by pressing button 2 👨‍💻 Алгоритм: 1⃣Объявите два массива динамического программирования length и count, и инициализируйте их значениями length[i]=1 и count[i]=1. Итерируйте i от 0 до n−1. Для каждого i итерируйте j от 0 до i−1 и, если nums[j] < nums[i], обновите length[i] и count[i] в зависимости от значений length[j] и count[j]. 2⃣Найдите максимальное значение в массиве length и сохраните его в переменной maxLength. Инициализируйте переменную result = 0. 3⃣Итерируйте i от 0 до n−1 и, если length[i] = maxLength, добавьте count[i] к result. Верните result. 😎 Решение: class Solution { fun findNumberOfLIS(nums: IntArray): Int { val n = nums.size val length = IntArray(n) { 1 } val count = IntArray(n) { 1 } for (i in 0 until n) { for (j in 0 until i) { if (nums[j] < nums[i]) { if (length[j] + 1 > length[i]) { length[i] = length[j] + 1 count[i] = 0 } if (length[j] + 1 == length[i]) { count[i] += count[j] } } } } val maxLength = length.maxOrNull() ?: 0 var result = 0 for (i in 0 until n) { if (length[i] == maxLength) { result += count[i] } } return result } } Ставь 👍 и забирай 📚 Базу знаний
99
5
Задача: 57. Insert Interval Сложность: medium Вам дан массив непересекающихся интервалов intervals, где intervals[i] = [starti, endi] представляет начало и конец i-го интервала, и массив intervals отсортирован в порядке возрастания по starti. Вам также дан интервал newInterval = [start, end], представляющий начало и конец другого интервала. Вставьте newInterval в массив intervals так, чтобы intervals оставался отсортированным в порядке возрастания по starti и в intervals не было бы перекрывающихся интервалов (при необходимости объедините перекрывающиеся интервалы). Верните массив intervals после вставки. Обратите внимание, что не обязательно модифицировать массив intervals на месте. Вы можете создать новый массив и вернуть его. Пример: Input: intervals = [[1,3],[6,9]], newInterval = [2,5] Output: [[1,5],[6,9]] 👨‍💻 Алгоритм: 1⃣ Инициализация переменных: Инициализируются переменные n и i для хранения размера массива интервалов и текущего индекса соответственно, а также пустой массив res для хранения результата. 2⃣Обработка случаев без перекрытия и с перекрытием: В случае отсутствия перекрытия до вставки, проходим через массив интервалов до тех пор, пока конечная точка текущего интервала меньше начальной точки нового интервала. Добавляем текущий интервал в массив res и переходим к следующему. В случае перекрытия, продолжаем обход, пока начальная точка нового интервала меньше или равна конечной точке текущего интервала. Обновляем начальные и конечные точки нового интервала, объединяя перекрывающиеся интервалы в один. 3⃣Обработка интервалов после вставки: Проходим через оставшиеся интервалы после индекса i и добавляем их в массив res. Это включает интервалы, которые следуют после нового интервала и не перекрываются с ним. Возвращаем массив res, содержащий все интервалы с корректно вставленным новым интервалом. 😎 Решение: class Solution { fun insert(intervals: List<List<Int>>, newInterval: MutableList<Int>): List<List<Int>> { val n = intervals.size var i = 0 val res = mutableListOf<List<Int>>() while (i < n && intervals[i][1] < newInterval[0]) { res.add(intervals[i]) i++ } while (i < n && newInterval[1] >= intervals[i][0]) { newInterval[0] = minOf(newInterval[0], intervals[i][0]) newInterval[1] = maxOf(newInterval[1], intervals[i][1]) i++ } res.add(newInterval) while (i < n) { res.add(intervals[i]) i++ } return res } } Ставь 👍 и забирай 📚 Базу знаний
101
6
Задача: 751. IP to CIDR Сложность: medium Дан указатель на начало односвязного списка и два целых числа left и right, где left <= right. Необходимо перевернуть узлы списка, начиная с позиции left и заканчивая позицией right, и вернуть измененный список. Пример: Input: ip = "255.0.0.7", n = 10 Output: ["255.0.0.7/32","255.0.0.8/29","255.0.0.16/32"] 👨‍💻 Алгоритм: 1⃣Преобразовать начальный IP-адрес в целое число. 2⃣Пока количество оставшихся IP-адресов n больше нуля: Определить наибольший блок, который начинается с текущего IP-адреса и не превышает количество оставшихся IP-адресов. Добавить этот блок к результату. Увеличить текущий IP-адрес на размер блока. Уменьшить количество оставшихся IP-адресов n. 3⃣Преобразовать блоки обратно в формат CIDR и вернуть их. 😎 Решение: fun ipToInt(ip: String): Int { val parts = ip.split(".").map { it.toInt() } return (parts[0] shl 24) + (parts[1] shl 16) + (parts[2] shl 8) + parts[3] } fun intToIp(num: Int): String { return "${(num shr 24) and 255}.${(num shr 16) and 255}.${(num shr 8) and 255}.${num and 255}" } fun cidr(ip: String, prefixLength: Int): String { return "$ip/$prefixLength" } fun findCidrBlocks(startIp: String, n: Int): List<String> { var start = ipToInt(startIp) val result = mutableListOf<String>() var remaining = n while (remaining > 0) { var maxSize = 1 while (maxSize <= start && maxSize <= remaining) { maxSize = maxSize shl 1 } maxSize = maxSize shr 1 while (start % maxSize != 0) { maxSize = maxSize shr 1 } result.add(cidr(intToIp(start), 32 - Integer.bitCount(maxSize - 1) + 1)) start += maxSize remaining -= maxSize } return result } Ставь 👍 и забирай 📚 Базу знаний
104
7
Задача: 935. Knight Dialer Сложность: medium Шахматный конь обладает уникальным движением: он может перемещаться на две клетки по вертикали и одну клетку по горизонтали, или на две клетки по горизонтали и одну клетку по вертикали (при этом обе клетки образуют форму буквы L). Возможные движения шахматного коня показаны на этой диаграмме: Шахматный конь может двигаться так, как показано на шахматной диаграмме ниже: У нас есть шахматный конь и телефонная панель, как показано ниже, конь может стоять только на числовой клетке (то есть на синей клетке). Учитывая целое число n, верните, сколько различных телефонных номеров длины n мы можем набрать. Вам разрешается сначала поставить коня на любую цифровую клетку, а затем выполнить n - 1 прыжков, чтобы набрать номер длины n. Все прыжки должны быть правильными прыжками коня. Поскольку ответ может быть очень большим, верните ответ по модулю 10^9 + 7. Пример: Input: n = 1 Output: 10 👨‍💻 Алгоритм: 1⃣Определить возможные движения коня с каждой цифровой клетки. Использовать динамическое программирование для хранения количества способов достижения каждой цифровой клетки на каждом шаге. 2⃣Инициализировать массив DP количеством способов набора телефонного номера длины 1 для каждой цифровой клетки (это просто 1). На каждом шаге обновлять массив DP, переходя по всем возможным движениям коня. 3⃣Вернуть сумму всех значений в массиве DP на последнем шаге. 😎 Решение: class Solution { fun knightDialer(n: Int): Int { val MOD = 1000000007 val moves = arrayOf( intArrayOf(4, 6), intArrayOf(6, 8), intArrayOf(7, 9), intArrayOf(4, 8), intArrayOf(0, 3, 9), intArrayOf(), intArrayOf(0, 1, 7), intArrayOf(2, 6), intArrayOf(1, 3), intArrayOf(2, 4) ) var dp = IntArray(10) { 1 } for (step in 1 until n) { val newDp = IntArray(10) for (i in 0 until 10) { for (move in moves[i]) { newDp[move] = (newDp[move] + dp[i]) % MOD } } dp = newDp } return dp.fold(0) { acc, count -> (acc + count) % MOD } } } Ставь 👍 и забирай 📚 Базу знаний
109
8
Осталось 3 часа до конца акции: «Пожизненный PRO тариф — по цене 1 года» Поиск работы отнимает силы, время и веру в себя, но
Осталось 3 часа до конца акции: «Пожизненный PRO тариф — по цене 1 года» Поиск работы отнимает силы, время и веру в себя, но не у тех кто использует easyoffer PRO. Успей сделать самую выгодную инвестицию в развитие своей карьеры. Акция закончится уже сегодня 23 июня 23:59 по мск: 👉 https://easyoffer.ru/pro
46
9
Последний день акции: «Пожизненный PRO тариф — по цене 1 года» 🚀 PRO включает: – Полный доступ ко всем грейдам и профессиям
Последний день акции: «Пожизненный PRO тариф — по цене 1 года» 🚀 PRO включает: – Полный доступ ко всем грейдам и профессиям – База live-coding задач и вопросов из технических собеседований с вероятностью их встречи – Примеры лучших ответов от Senior разработчиков – 1100+ записи реальных собеседований, в том числе в топовые компании (Сбер, Авито, Яндекс, WB, OZON, МТС и др.) – База 400+ тестовых заданий от компаний. – Автоотклики на вакансии в хедхантер – Аналитика ТОП-требований из вакансий для лучшего написания резюме и прохождения ATS систем рекрутеров – Генератор уникального резюме и CV под каждую вакансию – Тренажеры подготовки к собеседованию: «Реальное собеседование» и «Проработка вопросов» по методике интервальных повторений (как Anki) – (скоро) Агрегатор вакансий – (скоро) Сообщество Акция закончится уже сегодня 23 июня 23:59 по мск: 👉 https://easyoffer.ru/pro
88
10
Задача: 841. Keys and Rooms Сложность: medium Есть n комнат, пронумерованных от 0 до n - 1, и все комнаты закрыты, кроме комнаты 0. Ваша цель — посетить все комнаты. Однако вы не можете войти в закрытую комнату, не имея ключа от нее. Когда вы посещаете комнату, вы можете найти в ней набор различных ключей. Каждый ключ имеет номер, указывающий, какую комнату он открывает, и вы можете взять их все с собой, чтобы открыть другие комнаты. Дан массив rooms, где rooms[i] — это набор ключей, которые вы можете получить, если посетите комнату i. Верните true, если вы можете посетить все комнаты, или false в противном случае. Пример: Input: rooms = [[1],[2],[3],[]] Output: true Explanation: We visit room 0 and pick up key 1. We then visit room 1 and pick up key 2. We then visit room 2 and pick up key 3. We then visit room 3. Since we were able to visit every room, we return true. 👨‍💻 Алгоритм: 1⃣Создайте массив seen для отслеживания посещенных комнат и стек stack для ключей, которые нужно использовать. 2⃣Поместите ключ от комнаты 0 в стек и отметьте комнату 0 как посещенную. 3⃣Пока стек не пуст, извлекайте ключи из стека и используйте их для открытия новых комнат, добавляя найденные ключи в стек. Если все комнаты посещены, верните true, иначе false. 😎 Решение: class Solution { fun canVisitAllRooms(rooms: List<List<Int>>): Boolean { val seen = BooleanArray(rooms.size) { false } seen[0] = true val stack = Stack<Int>() stack.push(0) while (stack.isNotEmpty()) { val node = stack.pop() for (nei in rooms[node]) { if (!seen[nei]) { seen[nei] = true stack.push(nei) } } } return seen.all { it } } } Ставь 👍 и забирай 📚 Базу знаний
140
11
Пожизненный PRO тариф — по цене 1 года. Покупаешь один раз — пользуешься всю жизнь: 👉 https://easyoffer.ru/pro 🚀 PRO-доступ
Пожизненный PRO тариф — по цене 1 года. Покупаешь один раз — пользуешься всю жизнь: 👉 https://easyoffer.ru/pro 🚀 PRO-доступ закроет 99% проблем на пути к офферу: 1. Полный доступ ко всем грейдам и профессиям. Не важно, Junior вы или Senior, Тестировщик, Разработчик, Проджект — вы получите материалы под ваш текущий уровень и цели, без ограничений. 2. База live-coding задач и вопросов с реальных собесов с уникальной системой вероятности их встречи. Вы будете готовиться не вслепую, а точечно по тем темам, которые спрашивают чаще всего. 3. Эталонные ответы от Senior-разработчиков. Никакой воды и догадок — только четкие, структурированные решения, за которые дают «зеленый свет» к офферу 4. 1100+ записей реальных собеседований (включая топы: Сбер, Авито, Яндекс, WB, OZON, МТС). Вы увидите всё изнутри: как спрашивают, как отвечают сильные кандидаты и на каких ошибках проваливаются 80% проходящих. 5. База 400+ тестовых заданий. Если вы еще студент, то практикуйтесь на решении задач, которые помогут попасть на собес 6. Автоотклики на Хедхантере — пока вы спите, ваше резюме летит к рекрутерам автоматически. Это экономия сотен часов ручного кликанья. 7. Аналитика ТОП-требований из вакансий. Мы парсим рынок и показываем, какие скиллы сейчас в цене. Это позволит вам точечно апгрейдить резюме и проходить суровые ATS-фильтры (которые отсеивают до 75% резюме еще до просмотра рекрутером). 8. Генератор уникального резюме и CV под каждую вакансию. Забудьте про «универсальное» резюме — нейросеть адаптирует ваш опыт под конкретную позицию за минуту, повышая шансы на приглашение в разы. 9. Тренажеры подготовки к собеседованию: «Реальное собеседование» — сценарий вопросов из реальных интервью «Проработка вопросов» — флеш карточки с вопросами/ответами по методике интервальных повторений (как Anki) 10. (Скоро) Агрегатор вакансий — все вакансии из HH, Telegram, LinkedIn и других площадок в одной ленте. 11. (Скоро) Закрытое комьюнити — нетворкинг и помощь в сложных вопросах от таких же целеустремленных айтишников. Завтра последний день акции: 👉 https://easyoffer.ru/pro
92
12
Задача: 1255. Maximum Score Words Formed by Letters Сложность: hard Даны список слов, список отдельных букв (могут повторяться) и оценка каждого символа. Верните максимальную оценку любого правильного набора слов, образованного с помощью заданных букв (words[i] не может быть использовано два или более раз). Не обязательно использовать все символы в буквах, каждая буква может быть использована только один раз. Оценка букв 'a', 'b', 'c', ... , 'z' задаются значениями score[0], score[1], ... , score[25] соответственно. Пример: Input: words = ["dog","cat","dad","good"], letters = ["a","a","c","d","d","d","g","o","o"], score = [1,0,9,5,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0] Output: 23 👨‍💻 Алгоритм: 1⃣Создайте функцию для вычисления оценки слова. 2⃣Используйте метод перебора подмножеств (или битовое представление всех подмножеств) для нахождения всех возможных комбинаций слов. Для каждой комбинации проверяйте, можно ли составить каждое слово из доступных букв. 3⃣Вычислите суммарную оценку для каждой допустимой комбинации слов и сохраните максимальную оценку. 😎 Решение: class Solution { fun maxScoreWords(words: Array<String>, letters: CharArray, score: IntArray): Int { val letterCount = mutableMapOf<Char, Int>() letters.forEach { letterCount[it] = letterCount.getOrDefault(it, 0) + 1 } fun wordScore(word: String): Int { var total = 0 for (ch in word) { total += score[ch - 'a'] } return total } fun canFormWord(word: String, letterCount: Map<Char, Int>): Boolean { val count = mutableMapOf<Char, Int>() for (ch in word) { count[ch] = count.getOrDefault(ch, 0) + 1 if (count[ch]!! > letterCount.getOrDefault(ch, 0)) { return false } } return true } var maxScore = 0 val n = words.size for (i in 1 until (1 shl n)) { var currScore = 0 val usedLetters = mutableMapOf<Char, Int>() var valid = true for (j in 0 until n) { if (i and (1 shl j) != 0) { val word = words[j] if (canFormWord(word, letterCount)) { currScore += wordScore(word) for (ch in word) { usedLetters[ch] = usedLetters.getOrDefault(ch, 0) + 1 } } else { valid = false break } } } if (valid) { maxScore = maxOf(maxScore, currScore) } } return maxScore } } Ставь 👍 и забирай 📚 Базу знаний
91
13
Задача: 136. Single Number Сложность: easy Дан непустой массив целых чисел nums, в котором каждый элемент встречается дважды, кроме одного. Найдите этот единственный элемент. Вы должны реализовать решение с линейной сложностью выполнения и использовать только постоянное дополнительное пространство. Пример: Input: nums = [2,2,1] Output: 1 👨‍💻 Алгоритм: 1⃣Переберите все элементы в массиве nums. 2⃣Если какое-то число в nums новое для массива, добавьте его. 3⃣Если какое-то число уже есть в массиве, удалите его. 😎 Решение: fun singleNumber(nums: IntArray): Int { val noDuplicateList = mutableListOf<Int>() for (i in nums) { if (i !in noDuplicateList) { noDuplicateList.add(i) } else { noDuplicateList.removeAll { it == i } } } return noDuplicateList.firstOrNull() ?: 0 } Ставь 👍 и забирай 📚 Базу знаний
115
14
Задача: 838. Push Dominoes Сложность: medium Есть n домино, выстроенные в линию, и каждое домино стоит вертикально. Вначале мы одновременно толкаем некоторые домино либо влево, либо вправо. Через каждую секунду каждое падающее влево домино толкает соседнее домино слева. Точно так же домино, падающие вправо, толкают соседние домино, стоящие справа. Когда вертикальное домино оказывается под воздействием падающих домино с обеих сторон, оно остаётся неподвижным из-за баланса сил. В рамках этой задачи мы будем считать, что падающее домино не передаёт дополнительную силу падающему или уже упавшему домино. Вам дано строковое представление начального состояния домино: dominoes[i] = 'L', если i-е домино толкнули влево, dominoes[i] = 'R', если i-е домино толкнули вправо, и dominoes[i] = '.', если i-е домино не было толкнуто. Верните строку, представляющую конечное состояние. Пример: Input: dominoes = ".L.R...LR..L.." Output: "LL.RR.LLRRLL.." 👨‍💻 Алгоритм: 1⃣Пройдите по строке и сохраните индексы и символы не пустых домино в массивы. 2⃣Добавьте фиктивные домино 'L' в начале и 'R' в конце для упрощения логики. 3⃣Обработайте промежутки между соседними домино, обновляя их состояния согласно правилам. 😎 Решение: class Solution { fun pushDominoes(dominoes: String): String { val N = dominoes.length val indexes = mutableListOf(-1) val symbols = mutableListOf('L') for (i in dominoes.indices) { if (dominoes[i] != '.') { indexes.add(i) symbols.add(dominoes[i]) } } indexes.add(N) symbols.add('R') val ans = dominoes.toCharArray() for (idx in 0 until indexes.size - 1) { val i = indexes[idx] val j = indexes[idx + 1] val x = symbols[idx] val y = symbols[idx + 1] if (x == y) { for (k in i + 1 until j) { ans[k] = x } } else if (x == 'R' && y == 'L') { for (k in i + 1 until j) { if (k - i == j - k) { ans[k] = '.' } else if (k - i < j - k) { ans[k] = 'R' } else { ans[k] = 'L' } } } } return String(ans) } Ставь 👍 и забирай 📚 Базу знаний
111
15
Привет, ребята! У нас для вас отличные новости — на easyoffer вышло сразу несколько крупных обновлений: 1. Автоотклики на HeadHunter Снова работают в полную силу — можно смело возвращаться к активному поиску. 2. Новый раздел «Резюмейкер» Теперь вы можете быстро создавать уникальные резюме, адаптированные под каждую вакансию, и сразу добавлять сопроводительное письмо. Это заметно повышает шансы получить приглашение на собеседование. 3. База вопросов стала чище Мы навели порядок и удалили около 30% дубликатов. Ориентироваться стало проще. –––––––––––––––––– 🔥 Акция в честь обновления Пожизненный тариф easyoffer PRO — по цене одного года. Успейте до 23 июня: 👉 https://easyoffer.ru/pro –––––––––––––––––– Что дальше? В ближайшие пару недель добавим ещё два раздела: 1. Сообщество с чатами по всем профессиональным направлениям. 2. Агрегатор вакансий, чтобы поиск работы стал ещё удобнее.
89
16
Задача: 219. Contains Duplicate II Сложность: easy Дан массив целых чисел nums и целое число k. Верните true, если в массиве существуют два различных индекса i и j, такие что nums[i] == nums[j] и abs(i - j) <= k. Пример: Input: nums = [1,2,3,1,2,3], k = 2 Output: false 👨‍💻 Алгоритм: 1⃣Создайте пустое множество set. 2⃣Пройдитесь по массиву nums: Если текущий элемент уже есть в множестве, верните true. Добавьте текущий элемент в множество. Если размер множества больше k, удалите элемент, который был добавлен k шагов назад. 3⃣Если не найдены дублирующиеся элементы на расстоянии k или менее, верните false. 😎 Решение: class Solution { fun containsNearbyDuplicate(nums: IntArray, k: Int): Boolean { val set = mutableSetOf<Int>() for (i in nums.indices) { if (set.contains(nums[i])) return true set.add(nums[i]) if (set.size > k) set.remove(nums[i - k]) } return false } } Ставь 👍 и забирай 📚 Базу знаний
116
17
Задача: 1063. Number of Valid Subarrays Сложность: hard Дан целочисленный массив nums. Вернуть количество непустых подмассивов, в которых левый элемент не больше других элементов подмассива. Подмассив — это непрерывная часть массива. Пример: Input: nums = [1,4,2,5,3] Output: 11 Explanation: There are 11 valid subarrays: [1],[4],[2],[5],[3],[1,4],[2,5],[1,4,2],[2,5,3],[1,4,2,5],[1,4,2,5,3]. 👨‍💻 Алгоритм: 1⃣нициализируйте переменную ans значением 0. Инициализируйте пустой стек st, который будет хранить индексы элементов в стеке. 2⃣Итерируйте по элементам массива nums для каждого индекса i: продолжайте извлекать элементы из стека st, пока стек не станет пустым или элемент nums[i] не станет больше элемента на вершине стека. Для каждого извлеченного элемента добавляйте количество подмассивов как i - st.top(). Поместите текущий индекс i в стек. 3⃣Извлеките все оставшиеся элементы из стека и для каждого рассмотрите размер nums как индекс следующего меньшего элемента. Соответственно, добавьте nums.size() - st.top() к переменной ans. Верните ans. 😎 Решение: class Solution { fun validSubarrays(nums: IntArray): Int { var ans = 0 val st = mutableListOf<Int>() for (i in nums.indices) { while (st.isNotEmpty() && nums[i] < nums[st.last()]) { ans += (i - st.removeAt(st.size - 1)) } st.add(i) } while (st.isNotEmpty()) { ans += (nums.size - st.removeAt(st.size - 1)) } return ans } } Ставь 👍 и забирай 📚 Базу знаний
136
18
Задача: 726. Number of Atoms Сложность: hard Если задана строковая формула, представляющая химическую формулу, верните количество атомов. Атомный элемент всегда начинается с прописного символа, затем ноль или более строчных букв, представляющих его название. Если количество больше 1, за ним может следовать одна или более цифр, представляющих количество элементов. Например, "H2O" и "H2O2" возможны, а "H1O2" невозможен. Две формулы объединяются вместе, чтобы получить другую формулу. Например, "H2O2He3Mg4" также является формулой. Формула, заключенная в круглые скобки, и счет (по желанию) также являются формулами. Например, "(H2O2)" и "(H2O2)3" являются формулами. Возвращает количество всех элементов в виде строки в следующем виде: первое имя (в отсортированном порядке), затем его количество (если это количество больше 1), затем второе имя (в отсортированном порядке), затем его количество (если это количество больше 1) и т. д. Тестовые примеры генерируются таким образом, чтобы все значения в выводе помещались в 32-битное целое число. Пример: Input: formula = "H2O" Output: "H2O" 👨‍💻 Алгоритм: 1⃣Используйте стек для отслеживания текущего уровня скобок. 2⃣Пройдите по строке формулы, анализируя каждый символ: Если символ - это открывающая скобка '(', создайте новый словарь для хранения атомов внутри скобок. Если символ - это закрывающая скобка ')', извлеките словарь из стека и умножьте количества атомов на последующее число, если оно присутствует. Если символ - это атом (начинается с заглавной буквы), извлеките имя атома и его количество, и добавьте его в текущий словарь. 3⃣После завершения обработки строки, объедините все словари из стека и отсортируйте результат. 😎 Решение: class Solution { fun countOfAtoms(formula: String): String { val stack = ArrayDeque<MutableMap<String, Int>>() stack.push(mutableMapOf()) var i = 0 val n = formula.length while (i < n) { if (formula[i] == '(') { stack.push(mutableMapOf()) i++ } else if (formula[i] == ')') { val top = stack.pop() i++ var multiplicity = 0 while (i < n && formula[i].isDigit()) { multiplicity = multiplicity * 10 + (formula[i] - '0') i++ } multiplicity = if (multiplicity == 0) 1 else multiplicity for ((name, count) in top) { stack.peek()[name] = stack.peek().getOrDefault(name, 0) + count * multiplicity } } else { var start = i i++ while (i < n && formula[i].isLowerCase()) { i++ } val name = formula.substring(start, i) start = i var multiplicity = 0 while (i < n && formula[i].isDigit()) { multiplicity = multiplicity * 10 + (formula[i] - '0') i++ } multiplicity = if (multiplicity == 0) 1 else multiplicity stack.peek()[name] = stack.peek().getOrDefault(name, 0) + multiplicity } } val countMap = stack.pop() val result = StringBuilder() for (name in countMap.keys.sorted()) { result.append(name) val count = countMap[name]!! if (count > 1) { result.append(count) } } return result.toString() } } Ставь 👍 и забирай 📚 Базу знаний
136
19
Задача: 1143. Longest Common Subsequence Сложность: medium Даны две строки text1 и text2. Верните длину их наибольшей общей подпоследовательности. Если общей подпоследовательности нет, верните 0. Подпоследовательность строки — это новая строка, созданная из оригинальной строки путем удаления некоторых символов (может быть ни одного) без изменения относительного порядка оставшихся символов. Например, "ace" является подпоследовательностью "abcde". Общая подпоследовательность двух строк — это подпоследовательность, которая является общей для обеих строк. Пример: Input: text1 = "abcde", text2 = "ace" Output: 3 Explanation: The longest common subsequence is "ace" and its length is 3. 👨‍💻 Алгоритм: 1⃣Создайте двумерный массив memo для хранения промежуточных результатов, чтобы избежать повторных вычислений. Инициализируйте массив значением -1, чтобы указать, что эти ячейки еще не были рассчитаны. 2⃣Реализуйте рекурсивную функцию memoSolve, которая принимает два указателя на текущие позиции в text1 и text2 и возвращает длину наибольшей общей подпоследовательности для этих подстрок. Если текущие символы совпадают, добавьте 1 к результату рекурсивного вызова для следующих символов. Если не совпадают, найдите максимум между рекурсивными вызовами с измененными указателями. 3⃣Возвращайте значение memoSolve(0, 0), чтобы получить результат для всей строки. 😎 Решение: class Solution { private lateinit var memo: Array<IntArray> private lateinit var text1: String private lateinit var text2: String fun longestCommonSubsequence(text1: String, text2: String): Int { this.text1 = text1 this.text2 = text2 memo = Array(text1.length + 1) { IntArray(text2.length + 1) { -1 } } return memoSolve(0, 0) } private fun memoSolve(p1: Int, p2: Int): Int { if (p1 == text1.length || p2 == text2.length) return 0 if (memo[p1][p2] != -1) return memo[p1][p2] val answer: Int if (text1[p1] == text2[p2]) { answer = 1 + memoSolve(p1 + 1, p2 + 1) } else { answer = maxOf(memoSolve(p1, p2 + 1), memoSolve(p1 + 1, p2)) } memo[p1][p2] = answer return answer } } Ставь 👍 и забирай 📚 Базу знаний
139
20
Задача: 1029. Two City Scheduling Сложность: medium Компания планирует провести интервью с 2n людьми. Учитывая массив costs, где costs[i] = [aCosti, bCosti], стоимость перелета i-го человека в город a равна aCosti, а стоимость перелета i-го человека в город b равна bCosti. Выведите минимальную стоимость перелета каждого человека в город, чтобы в каждый город прибыло ровно n человек. Пример: Input: traversal = "1-2--3--4-5--6--7" Output: [1,2,5,3,4,6,7] 👨‍💻 Алгоритм: 1⃣Вычислить разницу стоимости: Для каждого человека вычислите разницу в стоимости между перелетом в город A и город B. 2⃣Сортировать по разнице: Отсортируйте людей по разнице в стоимости перелета в город A и B. Это поможет минимизировать общую стоимость, так как мы сначала будем отправлять тех, для кого разница минимальна. 3⃣Назначить города: Первые n человек из отсортированного списка отправьте в город A. Оставшихся n человек отправьте в город B. 😎 Решение: class Solution { fun twoCitySchedCost(costs: Array<IntArray>): Int { costs.sortBy { it[0] - it[1] } var totalCost = 0 val n = costs.size / 2 for (i in 0 until n) { totalCost += costs[i][0] totalCost += costs[i + n][1] } return totalCost } } Ставь 👍 и забирай 📚 Базу знаний
156