ru
Feedback
Kotlin | LeetCode

Kotlin | LeetCode

Открыть в Telegram
1 726
Подписчики
-124 часа
-37 дней
-1230 день
Архив постов
Задача: 1295. Find Numbers with Even Number of Digits Сложность: easy Дан массив чисел nums. Верните количество чисел в массиве, которые содержат четное количество цифр. Пример:
Input: nums = [12,345,2,6,7896]
Output: 2
Explanation: 
12 contains 2 digits (even number of digits). 
345 contains 3 digits (odd number of digits). 
2 contains 1 digit (odd number of digits). 
6 contains 1 digit (odd number of digits). 
7896 contains 4 digits (even number of digits). 
Therefore only 12 and 7896 contain an even number of digits.
👨‍💻 Алгоритм: 1⃣Определите вспомогательную функцию hasEvenDigits, которая принимает num в качестве входных данных и возвращает true, если количество цифр четное, иначе возвращает false. 2⃣Внутри функции hasEvenDigits. Инициализируйте переменную digitCount значением 0. Пока num не равно нулю: Увеличивайте digitCount на 1. Делите num на 10. Возвращайте digitCount & 1 == 0. 3⃣В функции findNumbers. Инициализируйте переменную evenDigitCount значением 0. Для каждого числа num в массиве nums, проверяйте, возвращает ли hasEvenDigits(num) значение true. Если да, увеличивайте evenDigitCount на 1. Возвращайте evenDigitCount. 😎 Решение:
class Solution {
    fun hasEvenDigits(num: Int): Boolean {
        var digitCount = 0
        var num = num
        while (num > 0) {
            digitCount++
            num /= 10
        }
        return (digitCount and 1) == 0
    }

    fun findNumbers(nums: IntArray): Int {
        var evenDigitCount = 0
        for (num in nums) {
            if (hasEvenDigits(num)) {
                evenDigitCount++
            }
        }
        return evenDigitCount
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 1354. Construct Target Array With Multiple Sums Сложность: hard Дан массив целых чисел target длины n. Начав с массива arr, состоящего из n единиц, вы можете выполнить следующую процедуру: Пусть x будет суммой всех элементов, находящихся в вашем массиве. Выберите индекс i так, чтобы 0 <= i < n, и установите значение arr в индексе i равным x. Вы можете повторять эту процедуру столько раз, сколько потребуется. Верните true, если возможно построить массив target из arr, в противном случае верните false. Пример:
Input: target = [8,5]
Output: true
👨‍💻 Алгоритм: 1⃣Использование максимальной кучи (Max Heap) для отслеживания максимальных значений в target: Сначала необходимо инициализировать кучу с максимальным приоритетом, чтобы всегда иметь доступ к наибольшему элементу в массиве target. Вычислить сумму всех элементов в target и сохранить ее. 2⃣Повторение процесса переворота: Извлечь наибольшее значение из кучи. Вычесть это значение из общей суммы. Проверить несколько условий: Если извлеченное значение равно 1 или общая сумма равна 1, вернуть true. Если извлеченное значение меньше общей суммы, общая сумма равна 0, или извлеченное значение делится на общую сумму без остатка, вернуть false. Остаток от деления наибольшего значения на общую сумму является новым значением, которое нужно вставить обратно в кучу. Обновить общую сумму. 3⃣Повторение цикла до достижения результата: Повторять шаг 2 до тех пор, пока не будут выполнены условия выхода из цикла (возврат true или false). 😎 Решение:
import java.util.PriorityQueue

class Solution {
    fun isPossible(target: IntArray): Boolean {
        val pq = PriorityQueue<Int>(compareByDescending { it })
        var total = target.sum()
        target.forEach { pq.add(it) }
        
        while (pq.peek() > 1) {
            val maxVal = pq.poll()
            total -= maxVal
            if (maxVal < total || total == 0 || maxVal % total == 0) return false
            pq.add(maxVal % total)
            total += pq.peek()
        }
        return true
    }
}
Ставь 👍 и забирай 📚 Базу знаний

АЙТИШНИКИ, ХВАТИТ сливать время на прилизанные новости и бесполезные курсы Проект «ИИнтеллигенция» стал главным каналом для т
АЙТИШНИКИ, ХВАТИТ сливать время на прилизанные новости и бесполезные курсы Проект «ИИнтеллигенция» стал главным каналом для тех, кто использует нейросети на уровне разработки, автоматизации и опенсорса, а не просто балуется в чатах. Здесь собирают только то, что реально экономит человеко-часы и работает в проде. 🎓 Готовые ИИ-сервисы, промпты и ИИ-агенты для автоматизации рутины 📚 Разборы полезных ИИ-инструментов, локальных LLM и опенсорс-репозиториев 🛠 Практические кейсы, гайды по деплою моделей и интеграции ИИ в пайплайны ⚡️ Технические ИТ-новости без маркетинговой воды и душных отчетов Обучение и прокачка в реальном времени: работа с API (Claude, GPT), локалки (Ollama, vLLM), автоматизация кода, опенсорс-утилиты, AI-агенты и др. Ценишь время и работаешь с ИИ, подпишись: @clucai

Задача: 154. Find Minimum in Rotated Sorted Array II Сложность: hard Дан отсортированный по возрастанию массив nums, который был повёрнут от 1 до n раз и может содержать дубликаты. Нужно найти минимальный элемент массива с минимальным количеством операций. Пример:
Input: nums = [1,3,5]
Output: 1
👨‍💻 Алгоритм: 1⃣Сравниваем nums[mid] с nums[high], чтобы определить, в какой половине находится минимум: Если nums[mid] < nums[high], значит минимум в левой части (включая mid). Если nums[mid] > nums[high], минимум в правой части (после mid). 2⃣Если nums[mid] == nums[high], мы не можем определить сторону — сужаем диапазон на 1 справа (high -= 1), чтобы не потерять минимум. 3⃣Продолжаем бинарный поиск, пока low < high. Когда указатели сойдутся — это и есть индекс минимального элемента. 😎 Решение:
class Solution {
    fun findMin(nums: IntArray): Int {
        var low = 0
        var high = nums.size - 1
        
        while (low < high) {
            val pivot = low + (high - low) / 2
            when {
                nums[pivot] < nums[high] -> high = pivot
                nums[pivot] > nums[high] -> low = pivot + 1
                else -> high -= 1
            }
        }
        return nums[low]
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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) { _, _, _ -> }
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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()
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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 }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Осталось 3 часа до конца акции: «Пожизненный PRO тариф — по цене 1 года» Поиск работы отнимает силы, время и веру в себя, но
Осталось 3 часа до конца акции: «Пожизненный PRO тариф — по цене 1 года» Поиск работы отнимает силы, время и веру в себя, но не у тех кто использует easyoffer PRO. Успей сделать самую выгодную инвестицию в развитие своей карьеры. Акция закончится уже сегодня 23 июня 23:59 по мск: 👉 https://easyoffer.ru/pro

Последний день акции: «Пожизненный PRO тариф — по цене 1 года» 🚀 PRO включает: – Полный доступ ко всем грейдам и профессиям
Последний день акции: «Пожизненный PRO тариф — по цене 1 года» 🚀 PRO включает: – Полный доступ ко всем грейдам и профессиям – База live-coding задач и вопросов из технических собеседований с вероятностью их встречи – Примеры лучших ответов от Senior разработчиков – 1100+ записи реальных собеседований, в том числе в топовые компании (Сбер, Авито, Яндекс, WB, OZON, МТС и др.) – База 400+ тестовых заданий от компаний. – Автоотклики на вакансии в хедхантер – Аналитика ТОП-требований из вакансий для лучшего написания резюме и прохождения ATS систем рекрутеров – Генератор уникального резюме и CV под каждую вакансию – Тренажеры подготовки к собеседованию: «Реальное собеседование» и «Проработка вопросов» по методике интервальных повторений (как Anki) – (скоро) Агрегатор вакансий – (скоро) Сообщество Акция закончится уже сегодня 23 июня 23:59 по мск: 👉 https://easyoffer.ru/pro

Задача: 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 }
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Пожизненный 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

Задача: 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
    }
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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
}
Ставь 👍 и забирай 📚 Базу знаний

Задача: 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)
    }
Ставь 👍 и забирай 📚 Базу знаний

Привет, ребята! У нас для вас отличные новости — на easyoffer вышло сразу несколько крупных обновлений: 1. Автоотклики на HeadHunter Снова работают в полную силу — можно смело возвращаться к активному поиску. 2. Новый раздел «Резюмейкер» Теперь вы можете быстро создавать уникальные резюме, адаптированные под каждую вакансию, и сразу добавлять сопроводительное письмо. Это заметно повышает шансы получить приглашение на собеседование. 3. База вопросов стала чище Мы навели порядок и удалили около 30% дубликатов. Ориентироваться стало проще. –––––––––––––––––– 🔥 Акция в честь обновления Пожизненный тариф easyoffer PRO — по цене одного года. Успейте до 23 июня: 👉 https://easyoffer.ru/pro –––––––––––––––––– Что дальше? В ближайшие пару недель добавим ещё два раздела: 1. Сообщество с чатами по всем профессиональным направлениям. 2. Агрегатор вакансий, чтобы поиск работы стал ещё удобнее.

Задача: 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
    }
}
Ставь 👍 и забирай 📚 Базу знаний