Java | LeetCode
6.67K subscribers
219 photos
1.35K links
Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.me/+icUwivvbGOkwNWRi
Вопросы собесов t.me/+7ESm0VKXC4tjYzky
Вакансии t.me/+4pspF5nDjgM4MjQy
Download Telegram
Задача: 621. Task Scheduler
Сложность: medium

Вам дан массив задач процессора, каждая из которых представлена буквами от A до Z, и время охлаждения, n. Каждый цикл или интервал позволяет завершить одну задачу. Задачи могут быть выполнены в любом порядке, но есть ограничение: одинаковые задачи должны быть разделены не менее чем n интервалами из-за времени охлаждения. Верните минимальное количество интервалов, необходимое для выполнения всех задач.

Пример:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8


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

1⃣Подсчитайте количество каждой задачи и найдите максимальное количество вхождений (maxFreq).

2⃣Вычислите количество интервалов, необходимых для задач с maxFreq: (maxFreq - 1) * (n + 1) + countMaxFreq, где countMaxFreq - количество задач, имеющих maxFreq.

3⃣Верните максимум между вычисленным значением и длиной массива задач, поскольку некоторые задачи могут заполнять интервал до n.

😎 Решение:
import java.util.HashMap;
import java.util.Map;

public class Solution {
public int leastInterval(char[] tasks, int n) {
Map<Character, Integer> taskCounts = new HashMap<>();
for (char task : tasks) {
taskCounts.put(task, taskCounts.getOrDefault(task, 0) + 1);
}

int maxFreq = taskCounts.values().stream().max(Integer::compare).get();
int countMaxFreq = (int) taskCounts.values().stream().filter(count -> count == maxFreq).count();

return Math.max(tasks.length, (maxFreq - 1) * (n + 1) + countMaxFreq);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1339. Maximum Product of Splitted Binary Tree
Сложность: medium

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

Верните максимальное произведение сумм двух поддеревьев. Поскольку ответ может быть слишком большим, верните его по модулю 10^9 + 7.

Обратите внимание, что вам нужно максимально увеличить ответ до взятия модуля, а не после.

Пример:
Input: root = [1,2,3,4,5,6]
Output: 110
Explanation: Remove the red edge and get 2 binary trees with sum 11 and 10. Their product is 110 (11*10)


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

1⃣Рассчитать сумму значений всех узлов дерева и сохранить суммы всех поддеревьев в списке.

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

3⃣Найти максимальное произведение среди всех вычисленных и вернуть его значение по модулю 10^9 + 7.

😎 Решение:
class Solution {

private List<Integer> allSums = new ArrayList<>();

public int maxProduct(TreeNode root) {
long totalSum = treeSum(root);
long best = 0;
for (long sum : allSums) {
best = Math.max(best, sum * (totalSum - sum));
}
return (int)(best % 1000000007);
}

private int treeSum(TreeNode subroot) {
if (subroot == null) return 0;
int leftSum = treeSum(subroot.left);
int rightSum = treeSum(subroot.right);
int totalSum = leftSum + rightSum + subroot.val;
allSums.add(totalSum);
return totalSum;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 208. Implement Trie (Prefix Tree)
Сложность: medium

Trie (произносится как "трай") или префиксное дерево — это древовидная структура данных, используемая для эффективного хранения и поиска ключей в наборе строк. Существует множество применений этой структуры данных, таких как автозаполнение и проверка орфографии.

Реализуйте класс Trie:
Trie() инициализирует объект trie.
void insert(String word) вставляет строку word в trie.
boolean search(String word) возвращает true, если строка word есть в trie (то есть была вставлена ранее), и false в противном случае.
boolean startsWith(String prefix) возвращает true, если есть ранее вставленная строка word, которая имеет префикс prefix, и false в противном случае.

Пример:
Input
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
Output
[null, null, true, false, true, null, true]

Explanation
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // return True
trie.search("app"); // return False
trie.startsWith("app"); // return True
trie.insert("app");
trie.search("app"); // return True


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

1⃣Инициализация и вставка в Trie:
Создайте класс Trie, который включает в себя метод insert(String word) для добавления строк в Trie.
Метод insert инициализирует текущий узел как корень и проходит по каждому символу строки. Если текущий узел не содержит символа, создайте новый узел. В конце отметьте последний узел как конец слова.

2⃣Поиск строки в Trie:
Создайте метод search(String word), который использует вспомогательный метод searchPrefix(String word) для поиска строки или префикса в Trie.
В методе searchPrefix начните с корневого узла и для каждого символа строки перемещайтесь к следующему узлу. Если на каком-то этапе узел не содержит текущего символа, верните null. В противном случае, в конце строки верните текущий узел.

3⃣Проверка наличия префикса в Trie:
Создайте метод startsWith(String prefix), который также использует метод searchPrefix(String prefix).
Метод startsWith вызывает searchPrefix и возвращает true, если возвращаемый узел не равен null, что указывает на наличие префикса в Trie.

😎 Решение:
class TrieNode {
private TrieNode[] links = new TrieNode[26];
private boolean isEnd;

public boolean containsKey(char ch) {
return links[ch - 'a'] != null;
}

public TrieNode get(char ch) {
return links[ch - 'a'];
}

public void put(char ch, TrieNode node) {
links[ch - 'a'] = node;
}

public void setEnd() {
isEnd = true;
}

public boolean isEnd() {
return isEnd;
}
}

class Trie {
private TrieNode root = new TrieNode();

public void insert(String word) {
TrieNode node = root;
for (char ch : word.toCharArray()) {
if (!node.containsKey(ch)) {
node.put(ch, new TrieNode());
}
node = node.get(ch);
}
node.setEnd();
}

private TrieNode searchPrefix(String word) {
TrieNode node = root;
for (char ch : word.toCharArray()) {
if (node.containsKey(ch)) {
node = node.get(ch);
} else {
return null;
}
}
return node;
}

public boolean search(String word) {
TrieNode node = searchPrefix(word);
return node != null && node.isEnd();
}

public boolean startsWith(String prefix) {
return searchPrefix(prefix) != null;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 743. Network Delay Time
Сложность: medium

Дана сеть из узлов, помеченных от 1 до n. Также дано times - список времен прохождения сигнала в виде направленных ребер times[i] = (ui, vi, wi), где ui - исходный узел, vi - целевой узел, а wi - время прохождения сигнала от источника до цели. Мы пошлем сигнал из заданного узла k. Верните минимальное время, которое потребуется всем узлам, чтобы получить сигнал. Если все узлы не могут получить сигнал, верните -1.

Пример:
Input: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
Output: 2


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

1⃣Представьте граф в виде списка смежности.

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

3⃣Найдите максимальное значение среди кратчайших путей к узлам. Если какой-либо узел недостижим, верните -1.

😎 Решение:
import java.util.*;

public class Solution {
public int networkDelayTime(int[][] times, int n, int k) {
Map<Integer, List<int[]>> graph = new HashMap<>();
for (int i = 1; i <= n; i++) {
graph.put(i, new ArrayList<>());
}
for (int[] time : times) {
graph.get(time[0]).add(new int[]{time[1], time[2]});
}

PriorityQueue<int[]> minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
minHeap.add(new int[]{0, k});
Map<Integer, Integer> minTime = new HashMap<>();
for (int i = 1; i <= n; i++) {
minTime.put(i, Integer.MAX_VALUE);
}
minTime.put(k, 0);

while (!minHeap.isEmpty()) {
int[] top = minHeap.poll();
int time = top[0];
int node = top[1];
for (int[] neighbor : graph.get(node)) {
int newTime = time + neighbor[1];
if (newTime < minTime.get(neighbor[0])) {
minTime.put(neighbor[0], newTime);
minHeap.add(new int[]{newTime, neighbor[0]});
}
}
}

int maxTime = Collections.max(minTime.values());
return maxTime == Integer.MAX_VALUE ? -1 : maxTime;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1026. Maximum Difference Between Node and Ancestor
Сложность: medium

Учитывая корень бинарного дерева, найдите максимальное значение v, для которого существуют различные вершины a и b, где v = |a.val - b.val| и a является предком b. Вершина a является предком b, если: любой ребенок a равен b или любой ребенок a является предком b.

Пример:
Input: root = [8,3,10,1,6,null,14,null,null,4,7,13]
Output: 7


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

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

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

3⃣Рекурсивный вызов для детей:
Рекурсивно вызывайте функцию для левого и правого поддерева, передавая обновленные минимальное и максимальное значения.

😎 Решение:
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}

public class Solution {
public int maxAncestorDiff(TreeNode root) {
return dfs(root, root.val, root.val);
}

private int dfs(TreeNode node, int minVal, int maxVal) {
if (node == null) return maxVal - minVal;
minVal = Math.min(minVal, node.val);
maxVal = Math.max(maxVal, node.val);
int left = dfs(node.left, minVal, maxVal);
int right = dfs(node.right, minVal, maxVal);
return Math.max(left, right);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 644. Maximum Average Subarray II
Сложность: hard

Вам дан целочисленный массив nums, состоящий из n элементов, и целое число k. Найдите смежный подмассив, длина которого больше или равна k и который имеет максимальное среднее значение, и верните это значение. Принимается любой ответ с погрешностью вычислений менее 10-5.

Пример:
Input: nums = [1,12,-5,-6,50,3], k = 4
Output: 12.75000


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

1⃣Используйте скользящее окно длины k для нахождения начального среднего значения.

2⃣Перемещайте окно по массиву, добавляя следующий элемент и убирая предыдущий, обновляя текущее среднее значение.

3⃣Следите за максимальным средним значением и верните его после проверки всех возможных окон.

😎 Решение:
class Solution {
public double findMaxAverage(int[] nums, int k) {
int n = nums.length;
int currSum = 0;
for (int i = 0; i < k; i++) {
currSum += nums[i];
}
int maxSum = currSum;
for (int i = k; i < n; i++) {
currSum += nums[i] - nums[i - k];
if (currSum > maxSum) {
maxSum = currSum;
}
}
return maxSum / (double) k;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1437. Check If All 1's Are at Least Length K Places Away
Сложность: easy

Дан бинарный массив nums и целое число k. Вернуть true, если все единицы находятся на расстоянии не менее k позиций друг от друга, в противном случае вернуть false.

Пример:
Input: nums = [1,0,0,0,1,0,0,1], k = 2
Output: true
Explanation: Each of the 1s are at least 2 places away from each other.


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

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

2⃣Итерировать по массиву nums, проверяя, если текущий элемент равен 1. Если число нулей между единицами меньше k, вернуть false; иначе сбросить счетчик нулей на 0.

3⃣Если текущий элемент равен 0, увеличить счетчик нулей. В конце итерации вернуть true.

😎 Решение:
class Solution {
public boolean kLengthApart(int[] nums, int k) {
int count = k;
for (int num : nums) {
if (num == 1) {
if (count < k) {
return false;
}
count = 0;
} else {
count++;
}
}
return true;
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍1
Задача: 60. Permutation Sequence
Сложность: hard

Множество [1, 2, 3, ..., n] содержит в общей сложности n! уникальных перестановок.

Списком и маркировкой всех перестановок по порядку, мы получаем следующую последовательность для n = 3:

"123"
"132"
"213"
"231"
"312"
"321"
Дано n и k, верните k-ю перестановку последовательности.

Пример:
Input: n = 3, k = 3
Output: "213"


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

1⃣Сгенерируйте входной массив nums чисел от 1 до N.

2⃣Вычислите все факториальные основы от 0 до (N−1)!.

3⃣Уменьшите k на 1, чтобы значение попало в интервал (0, N!−1). Используйте коэффициенты факториалов для построения перестановки. Верните строку перестановки.

😎 Решение:
class Solution {
public String getPermutation(int n, int k) {
int[] factorials = new int[n];
List<Integer> nums = new ArrayList() {{
add(1);
}};

factorials[0] = 1;
for (int i = 1; i < n; ++i) {
factorials[i] = factorials[i - 1] * i;
nums.add(i + 1);
}

--k;

StringBuilder sb = new StringBuilder();
for (int i = n - 1; i > -1; --i) {
int idx = k / factorials[i];
k -= idx * factorials[i];

sb.append(nums.get(idx));
nums.remove(idx);
}
return sb.toString();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1200. Minimum Absolute Difference
Сложность: easy

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

Верните список пар в порядке возрастания (по отношению к парам), каждая пара [a, b] следует условиям:
a, b из arr
a < b
b - a равна минимальной абсолютной разнице между любыми двумя элементами в arr

Пример:
Input: arr = [4,2,1,3]
Output: [[1,2],[2,3],[3,4]]
Explanation: The minimum absolute difference is 1. List all pairs with difference equal to 1 in ascending order.


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

1⃣Инициализация вспомогательного массива:
Найдите минимальный элемент minElement и максимальный элемент maxElement в массиве arr.
Инициализируйте вспомогательный массив line размером maxElement - minElement + 1 и установите смещение shift равным -minElement.
Пройдите по массиву arr и для каждого элемента value увеличьте значение в индексе value + shift на 1.

2⃣Поиск минимальной абсолютной разницы:
Пройдите по вспомогательному массиву line, начиная с индекса, соответствующего минимальному элементу.
Проверьте значения на каждом индексе curr:
- если line[curr] равно 0, пропустите этот индекс.
- если line[curr] равно 1, сравните абсолютную разницу текущей пары currPairDiff с минимальной найденной разницей minPairDiff.
- если currPairDiff больше minPairDiff, продолжайте.
- если currPairDiff равно minPairDiff, добавьте эту пару в список ответов.
- если currPairDiff меньше minPairDiff, очистите список ответов, добавьте эту пару и обновите minPairDiff.

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

😎 Решение:
class Solution {
public List<List<Integer>> minimumAbsDifference(int[] arr) {
int minElement = arr[0];
int maxElement = arr[0];
for (int num : arr) {
minElement = Math.min(minElement, num);
maxElement = Math.max(maxElement, num);
}
int shift = -minElement;
int[] line = new int[maxElement - minElement + 1];
List<List<Integer>> answer = new ArrayList();

for (int num : arr) {
line[num + shift] = 1;
}

int minPairDiff = maxElement - minElement;
int prev = 0;

for (int curr = 1; curr <= maxElement + shift; ++curr) {
if (line[curr] == 0) {
continue;
}

if (curr - prev == minPairDiff) {
answer.add(Arrays.asList(prev - shift, curr - shift));
} else if (curr - prev < minPairDiff) {
answer = new ArrayList();
minPairDiff = curr - prev;
answer.add(Arrays.asList(prev - shift, curr - shift));
}

prev = curr;
}

return answer;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1258. Synonymous Sentences
Сложность: medium

Вам дан список эквивалентных пар строк synonyms, где synonyms[i] = [si, ti] означает, что si и ti являются эквивалентными строками. Вам также дан текст предложения. Верните все возможные синонимичные предложения, отсортированные лексикографически.

Пример:
Input: synonyms = [["happy","joy"],["sad","sorrow"],["joy","cheerful"]], text = "I am happy today but was sad yesterday"
Output: ["I am cheerful today but was sad yesterday","I am cheerful today but was sorrow yesterday","I am happy today but was sad yesterday","I am happy today but was sorrow yesterday","I am joy today but was sad yesterday","I am joy today but was sorrow yesterday"]


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

1⃣Построить граф синонимов, используя структуру данных, такую как Union-Find или просто с использованием DFS/BFS.

2⃣Пройти по каждому слову в предложении и найти все возможные синонимы.
Сгенерировать все возможные комбинации предложений.

3⃣Отсортировать полученные предложения лексикографически.

😎 Решение:
import java.util.*;

public class Solution {
public List<String> generateSentences(List<List<String>> synonyms, String text) {
Map<String, Set<String>> graph = new HashMap<>();
for (List<String> pair : synonyms) {
graph.computeIfAbsent(pair.get(0), k -> new HashSet<>()).add(pair.get(1));
graph.computeIfAbsent(pair.get(1), k -> new HashSet<>()).add(pair.get(0));
}

List<String> words = Arrays.asList(text.split(" "));
List<List<String>> synonymGroups = new ArrayList<>();
for (String word : words) {
synonymGroups.add(new ArrayList<>(findSynonyms(graph, word)));
}

List<String> sentences = new ArrayList<>();
generate(sentences, synonymGroups, new StringBuilder(), 0);
Collections.sort(sentences);
return sentences;
}

private Set<String> findSynonyms(Map<String, Set<String>> graph, String word) {
Set<String> synonyms = new HashSet<>();
Stack<String> stack = new Stack<>();
stack.push(word);
while (!stack.isEmpty()) {
String w = stack.pop();
if (synonyms.add(w)) {
stack.addAll(graph.getOrDefault(w, Collections.emptySet()));
}
}
return synonyms;
}

private void generate(List<String> sentences, List<List<String>> groups, StringBuilder sentence, int index) {
if (index == groups.size()) {
sentences.add(sentence.toString().trim());
return;
}
int len = sentence.length();
for (String word : groups.get(index)) {
sentence.append(" ").append(word);
generate(sentences, groups, sentence, index + 1);
sentence.setLength(len);
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM