Задача: 589. N-ary Tree Preorder Traversal
Сложность: easy
Дан корень N-арного дерева, верните значения его узлов в порядке предварительного (preorder) обхода.
Сериализация ввода N-арного дерева представлена в их обходе уровнями. Каждая группа детей разделена значением null (См. примеры).
Пример:
👨💻 Алгоритм:
1⃣ Инициализация
Создайте два списка: stack для хранения узлов и output для хранения значений узлов в порядке обхода. Добавьте корневой узел в stack.
2⃣ Итеративный обход
Пока stack не пуст, извлекайте узел из stack и добавляйте его значение в output. Разверните список дочерних узлов текущего узла и добавьте их в stack.
3⃣ Возврат результата
Верните список output как результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан корень N-арного дерева, верните значения его узлов в порядке предварительного (preorder) обхода.
Сериализация ввода N-арного дерева представлена в их обходе уровнями. Каждая группа детей разделена значением null (См. примеры).
Пример:
Input: root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
Output: [1,2,3,6,7,11,14,4,8,12,5,9,13,10]
Создайте два списка: stack для хранения узлов и output для хранения значений узлов в порядке обхода. Добавьте корневой узел в stack.
Пока stack не пуст, извлекайте узел из stack и добавляйте его значение в output. Разверните список дочерних узлов текущего узла и добавьте их в stack.
Верните список output как результат.
class Solution {
public List<Integer> preorder(Node root) {
LinkedList<Node> stack = new LinkedList<>();
LinkedList<Integer> output = new LinkedList<>();
if (root == null) {
return output;
}
stack.add(root);
while (!stack.isEmpty()) {
Node node = stack.pollLast();
output.add(node.val);
Collections.reverse(node.children);
for (Node item : node.children) {
stack.add(item);
}
}
return output;
}
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val,List<Node> _children) {
val = _val;
children = _children;
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 334. Increasing Triplet Subsequence
Сложность: medium
Дан массив целых чисел nums. Верните true, если существуют такие три индекса (i, j, k), что i < j < k и nums[i] < nums[j] < nums[k]. Если таких индексов не существует, верните false.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Создайте две переменные first_num и second_num и установите их значение на максимальное целое значение (Integer.MAX_VALUE или аналогичный максимум для выбранного языка программирования). Эти переменные будут хранить минимальные значения, необходимые для проверки существования возрастающей тройки.
2⃣ Итерация по массиву:
Пройдите по каждому элементу массива nums. Для каждого элемента выполните следующие проверки:
- если текущий элемент меньше или равен first_num, обновите first_num текущим элементом.
- иначе, если текущий элемент меньше или равен second_num, обновите second_num текущим элементом.
- иначе, если текущий элемент больше second_num, это означает, что найдена возрастающая тройка, поэтому верните true.
3⃣ Возврат результата:
Если после завершения итерации по массиву не была найдена возрастающая тройка, верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums. Верните true, если существуют такие три индекса (i, j, k), что i < j < k и nums[i] < nums[j] < nums[k]. Если таких индексов не существует, верните false.
Пример:
Input: nums = [2,1,5,0,4,6]
Output: true
Explanation: The triplet (3, 4, 5) is valid because nums[3] == 0 < nums[4] == 4 < nums[5] == 6.
Создайте две переменные first_num и second_num и установите их значение на максимальное целое значение (Integer.MAX_VALUE или аналогичный максимум для выбранного языка программирования). Эти переменные будут хранить минимальные значения, необходимые для проверки существования возрастающей тройки.
Пройдите по каждому элементу массива nums. Для каждого элемента выполните следующие проверки:
- если текущий элемент меньше или равен first_num, обновите first_num текущим элементом.
- иначе, если текущий элемент меньше или равен second_num, обновите second_num текущим элементом.
- иначе, если текущий элемент больше second_num, это означает, что найдена возрастающая тройка, поэтому верните true.
Если после завершения итерации по массиву не была найдена возрастающая тройка, верните false.
class Solution {
public boolean increasingTriplet(int[] nums) {
int first_num = Integer.MAX_VALUE;
int second_num = Integer.MAX_VALUE;
for (int n: nums) {
if (n <= first_num) {
first_num = n;
} else if (n <= second_num) {
second_num = n;
} else {
return true;
}
}
return false;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 978. Longest Turbulent Subarray
Сложность: medium
Дан целочисленный массив arr, верните длину максимального турбулентного подмассива массива arr.
Подмассив считается турбулентным, если знак сравнения меняется между каждой парой смежных элементов в подмассиве.
Более формально, подмассив [arr[i], arr[i + 1], ..., arr[j]] массива arr считается турбулентным тогда и только тогда, когда:
Для всех i <= k < j:
arr[k] > arr[k + 1], когда k нечетное, и
arr[k] < arr[k + 1], когда k четное.
Или, для всех i <= k < j:
arr[k] > arr[k + 1], когда k четное, и
arr[k] < arr[k + 1], когда k нечетное.
Пример:
👨💻 Алгоритм:
1⃣ Сканируйте массив слева направо. Используйте переменные для отслеживания начала текущего блока и максимальной длины турбулентного подмассива.
2⃣ Если достигли конца блока (последний элемент или текущий элемент не соответствует условию чередования), зафиксируйте длину этого блока как потенциальный ответ и установите начало нового блока на следующий элемент.
3⃣ Повторяйте шаг 2 до конца массива и верните максимальную длину турбулентного подмассива.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан целочисленный массив arr, верните длину максимального турбулентного подмассива массива arr.
Подмассив считается турбулентным, если знак сравнения меняется между каждой парой смежных элементов в подмассиве.
Более формально, подмассив [arr[i], arr[i + 1], ..., arr[j]] массива arr считается турбулентным тогда и только тогда, когда:
Для всех i <= k < j:
arr[k] > arr[k + 1], когда k нечетное, и
arr[k] < arr[k + 1], когда k четное.
Или, для всех i <= k < j:
arr[k] > arr[k + 1], когда k четное, и
arr[k] < arr[k + 1], когда k нечетное.
Пример:
Input: arr = [9,4,2,10,7,8,8,1,9]
Output: 5
Explanation: arr[1] > arr[2] < arr[3] > arr[4] < arr[5]
class Solution {
public int maxTurbulenceSize(int[] A) {
int N = A.length;
int ans = 1;
int anchor = 0;
for (int i = 1; i < N; ++i) {
int c = Integer.compare(A[i - 1], A[i]);
if (c == 0) {
anchor = i;
} else if (i == N - 1 || c * Integer.compare(A[i], A[i + 1]) != -1) {
ans = Math.max(ans, i - anchor + 1);
anchor = i;
}
}
return ans;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1248. Count Number of Nice Subarrays
Сложность: medium
Вам даны две строки s1 и s2 одинаковой длины, состоящие только из букв "x" и "y". Ваша задача - сделать эти две строки равными друг другу. Вы можете поменять местами любые два символа, принадлежащие разным строкам, что означает: поменять местами s1[i] и s2[j]. Верните минимальное количество обменов, необходимое для того, чтобы сделать s1 и s2 равными, или верните -1, если это невозможно сделать.
Пример:
👨💻 Алгоритм:
1⃣ Преобразуйте массив чисел nums, заменив все чётные числа на 0, а все нечётные числа на 1.
2⃣ Используя технику скользящего окна (или двух указателей), найдите все подмассивы, содержащие ровно k единиц.
3⃣ Подсчитайте количество таких подмассивов и верните этот результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам даны две строки s1 и s2 одинаковой длины, состоящие только из букв "x" и "y". Ваша задача - сделать эти две строки равными друг другу. Вы можете поменять местами любые два символа, принадлежащие разным строкам, что означает: поменять местами s1[i] и s2[j]. Верните минимальное количество обменов, необходимое для того, чтобы сделать s1 и s2 равными, или верните -1, если это невозможно сделать.
Пример:
Input: arr = [1,2]
Output: 2
public class Solution {
public int numberOfSubarrays(int[] nums, int k) {
return atMost(nums, k) - atMost(nums, k - 1);
}
private int atMost(int[] nums, int k) {
int res = 0, left = 0, count = 0;
for (int right = 0; right < nums.length; right++) {
if (nums[right] % 2 == 1) count++;
while (count > k) {
if (nums[left++] % 2 == 1) count--;
}
res += right - left + 1;
}
return res;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Задача: 91. Decode Ways
Сложность: medium
Строка s, содержащая только цифры, закодирована по соответствию: 'A' -> "1", 'B' -> "2", ..., 'Z' -> "26".
Нужно вернуть количество способов декодирования строки, учитывая, что '0' само по себе — невалидно, но может входить в состав двухзначного кода (например, "10").
Пример: Input: s = "12" Output: 2
Пояснение: "12" можно расшифровать как "AB" (1 2) или "L" (12)
Пример:
👨💻 Алгоритм:
1⃣ Запускаем рекурсивную функцию с позиции 0. Если дошли до конца строки — это один валидный путь (возвращаем 1). Если текущий символ '0', возвращаем 0.
2⃣ Проверяем, есть ли сохранённый результат для текущего индекса в memo. Если да — возвращаем его. Иначе вычисляем количество способов: один символ (если валидный) + два символа (если ≤ 26).
3⃣ Сохраняем результат для текущего индекса в memo и возвращаем общее количество способов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Строка s, содержащая только цифры, закодирована по соответствию: 'A' -> "1", 'B' -> "2", ..., 'Z' -> "26".
Нужно вернуть количество способов декодирования строки, учитывая, что '0' само по себе — невалидно, но может входить в состав двухзначного кода (например, "10").
Пример: Input: s = "12" Output: 2
Пояснение: "12" можно расшифровать как "AB" (1 2) или "L" (12)
Пример:
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).
class Solution {
Map<Integer, Integer> memo = new HashMap<>();
public int numDecodings(String s) {
return recursiveWithMemo(0, s);
}
private int recursiveWithMemo(int index, String str) {
if (memo.containsKey(index)) {
return memo.get(index);
}
if (index == str.length()) {
return 1;
}
if (str.charAt(index) == '0') {
return 0;
}
if (index == str.length() - 1) {
return 1;
}
int ans = recursiveWithMemo(index + 1, str);
if (Integer.parseInt(str.substring(index, index + 2)) <= 26) {
ans += recursiveWithMemo(index + 2, str);
}
memo.put(index, ans);
return ans;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 408. Valid Word Abbreviation
Сложность: easy
Строку можно сократить, заменив любое количество не смежных, непустых подстрок их длинами. Длины не должны содержать ведущих нулей.
Например, строка "замена" может быть сокращена следующим образом (но не ограничивается этим): "s10n" ("s ubstitutio n") "sub4u4" ("sub stit u tion") "12" ("замена") "su3i1u2on" ("su bst i t u ti on") "substitution" (без замены подстрок) Следующие сокращения не являются допустимыми:
"s55n" ("s ubsti tutio n", заменяемые подстроки смежные) "s010n" (содержит ведущие нули) "s0ubstitution" (заменяет пустую подстроку) Если задано строковое слово и аббревиатура abbr, верните, соответствует ли строка заданной аббревиатуре.
Подстрока - это непрерывная непустая последовательность символов в строке.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте два указателя: один для строки word и один для аббревиатуры abbr. Начните сравнение символов строки и аббревиатуры с начала.
2⃣ Если символ аббревиатуры - это цифра, вычислите полное число и переместите указатель строки word на это количество символов. Если символ аббревиатуры - это буква, убедитесь, что он совпадает с текущим символом строки.
3⃣ Повторяйте шаг 2, пока оба указателя не достигнут конца строки и аббревиатуры соответственно. Если это так, верните true, иначе false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Строку можно сократить, заменив любое количество не смежных, непустых подстрок их длинами. Длины не должны содержать ведущих нулей.
Например, строка "замена" может быть сокращена следующим образом (но не ограничивается этим): "s10n" ("s ubstitutio n") "sub4u4" ("sub stit u tion") "12" ("замена") "su3i1u2on" ("su bst i t u ti on") "substitution" (без замены подстрок) Следующие сокращения не являются допустимыми:
"s55n" ("s ubsti tutio n", заменяемые подстроки смежные) "s010n" (содержит ведущие нули) "s0ubstitution" (заменяет пустую подстроку) Если задано строковое слово и аббревиатура abbr, верните, соответствует ли строка заданной аббревиатуре.
Подстрока - это непрерывная непустая последовательность символов в строке.
Пример:
Input: word = "internationalization", abbr = "i12iz4n"
Output: true
public class Solution {
public boolean validWordAbbreviation(String word, String abbr) {
int i = 0, j = 0;
while (i < word.length() && j < abbr.length()) {
if (Character.isDigit(abbr.charAt(j))) {
if (abbr.charAt(j) == '0') {
return false;
}
int num = 0;
while (j < abbr.length() && Character.isDigit(abbr.charAt(j))) {
num = num * 10 + abbr.charAt(j) - '0';
j++;
}
i += num;
} else {
if (word.charAt(i) != abbr.charAt(j)) {
return false;
}
i++;
j++;
}
}
return i == word.length() && j == abbr.length();
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 99. Recover Binary Search Tree
Сложность: medium
Вам дан корень бинарного дерева поиска (BST), в котором значения ровно двух узлов дерева были поменяны местами по ошибке. Восстановите дерево, не изменяя его структуру.
Пример:
👨💻 Алгоритм:
1⃣ Создайте симметричный обход дерева. Это должен быть почти отсортированный список, в котором поменяны местами только два элемента.
2⃣ Определите два поменянных местами элемента x и y в почти отсортированном массиве за линейное время.
3⃣ Повторно пройдите по дереву. Измените значение x на y и значение y на x.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан корень бинарного дерева поиска (BST), в котором значения ровно двух узлов дерева были поменяны местами по ошибке. Восстановите дерево, не изменяя его структуру.
Пример:
Input: root = [1,3,null,null,2]
Output: [3,1,null,null,2]
Explanation: 3 cannot be a left child of 1 because 3 > 1. Swapping 1 and 3 makes the BST valid.
class Solution {
public void inorder(TreeNode root, List<Integer> nums) {
if (root == null) return;
inorder(root.left, nums);
nums.add(root.val);
inorder(root.right, nums);
}
public int[] findTwoSwapped(List<Integer> nums) {
int n = nums.size();
int x = -1, y = -1;
boolean swapped_first_occurrence = false;
for (int i = 0; i < n - 1; ++i) {
if (nums.get(i + 1) < nums.get(i)) {
y = nums.get(i + 1);
if (!swapped_first_occurrence) {
x = nums.get(i);
swapped_first_occurrence = true;
} else {
break;
}
}
}
return new int[] { x, y };
}
public void recover(TreeNode r, int count, int x, int y) {
if (r != null) {
if (r.val == x || r.val == y) {
r.val = r.val == x ? y : x;
if (--count == 0) return;
}
recover(r.left, count, x, y);
recover(r.right, count, x, y);
}
}
public void recoverTree(TreeNode root) {
List<Integer> nums = new ArrayList();
inorder(root, nums);
int[] swapped = findTwoSwapped(nums);
recover(root, 2, swapped[0], swapped[1]);
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1198. Find Smallest Common Element in All Rows
Сложность: medium
Дана матрица mat размером m x n, где каждая строка отсортирована в строго возрастающем порядке. Верните наименьший общий элемент во всех строках.
Если общего элемента нет, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Инициализируйте массив позиций pos, переменную для текущего максимального значения cur_max и счетчик cnt нулями.
2⃣ Итерация по строкам матрицы:
Для каждой строки:
- увеличивайте позицию в строке, пока значение не станет равным или больше текущего максимума.
- если достигли конца строки, возвращайте -1.
- если значение равно текущему максимуму, увеличивайте счетчик.
- в противном случае, сбросьте счетчик до 1 и обновите текущий максимум.
3⃣ Проверка счетчика:
Если счетчик равен количеству строк, возвращайте текущий максимум.
Повторите шаг 2.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана матрица mat размером m x n, где каждая строка отсортирована в строго возрастающем порядке. Верните наименьший общий элемент во всех строках.
Если общего элемента нет, верните -1.
Пример:
Input: mat = [[1,2,3,4,5],[2,4,5,8,10],[3,5,7,9,11],[1,3,5,7,9]]
Output: 5
Инициализируйте массив позиций pos, переменную для текущего максимального значения cur_max и счетчик cnt нулями.
Для каждой строки:
- увеличивайте позицию в строке, пока значение не станет равным или больше текущего максимума.
- если достигли конца строки, возвращайте -1.
- если значение равно текущему максимуму, увеличивайте счетчик.
- в противном случае, сбросьте счетчик до 1 и обновите текущий максимум.
Если счетчик равен количеству строк, возвращайте текущий максимум.
Повторите шаг 2.
public int smallestCommonElement(int[][] mat) {
int n = mat.length, m = mat[0].length;
int pos[] = new int[n], cur_max = 0, cnt = 0;
while (true) {
for (int i = 0; i < n; ++i) {
while (pos[i] < m && mat[i][pos[i]] < cur_max) {
++pos[i];
}
if (pos[i] >= m) {
return -1;
}
if (mat[i][pos[i]] != cur_max) {
cnt = 1;
cur_max = mat[i][pos[i]];
} else if (++cnt == n) {
return cur_max;
}
}
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 412. Fizz Buzz
Сложность: easy
Учитывая целое число n, верните строковый массив answer (с индексом 1), где: answer[i] == "FizzBuzz", если i делится на 3 и 5. answer[i] == "Fizz", если i делится на 3. answer[i] == "Buzz", если i делится на 5. answer[i] == i (как строка), если ни одно из перечисленных условий не верно.
Пример:
👨💻 Алгоритм:
1⃣ Создайте пустой список для хранения результата.
2⃣ Пройдите по всем числам от 1 до n и для каждого числа выполните проверку: Если число делится на 3 и на 5, добавьте "FizzBuzz". Если число делится на 3, добавьте "Fizz". Если число делится на 5, добавьте "Buzz". Если ни одно из условий не выполнено, добавьте само число как строку.
3⃣ Верните полученный список.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Учитывая целое число n, верните строковый массив answer (с индексом 1), где: answer[i] == "FizzBuzz", если i делится на 3 и 5. answer[i] == "Fizz", если i делится на 3. answer[i] == "Buzz", если i делится на 5. answer[i] == i (как строка), если ни одно из перечисленных условий не верно.
Пример:
Input: nums = [1,2,2]
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]
import java.util.ArrayList;
import java.util.List;
public class Solution {
public List<String> fizzBuzz(int n) {
List<String> answer = new ArrayList<>();
for (int i = 1; i <= n; i++) {
if (i % 3 == 0 && i % 5 == 0) {
answer.add("FizzBuzz");
} else if (i % 3 == 0) {
answer.add("Fizz");
} else if (i % 5 == 0) {
answer.add("Buzz");
} else {
answer.add(String.valueOf(i));
}
}
return answer;
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔4
Задача: 56. Merge Intervals
Сложность: medium
Дан массив интервалов, где intervals[i] = [starti, endi]. Объедините все перекрывающиеся интервалы и верните массив неперекрывающихся интервалов, которые покрывают все интервалы во входных данных.
Пример:
👨💻 Алгоритм:
1⃣ Представление графа:
Имея представленную интуицию, мы можем изобразить граф в виде списка смежности, вставляя направленные ребра в обоих направлениях, чтобы симулировать неориентированные ребра.
2⃣ Определение компонент связности:
Для определения, в какой компоненте связности находится каждый узел, мы выполняем обходы графа от произвольных непосещенных узлов до тех пор, пока все узлы не будут посещены. Для эффективности мы храним посещенные узлы в множестве (Set), что позволяет проводить проверки на принадлежность и вставку за константное время.
3⃣ Объединение интервалов внутри компонент:
Наконец, мы рассматриваем каждую связную компоненту, объединяя все её интервалы, создавая новый интервал с началом, равным минимальному началу среди всех интервалов в компоненте, и концом, равным максимальному концу.
Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив интервалов, где intervals[i] = [starti, endi]. Объедините все перекрывающиеся интервалы и верните массив неперекрывающихся интервалов, которые покрывают все интервалы во входных данных.
Пример:
Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlap, merge them into [1,6].
Имея представленную интуицию, мы можем изобразить граф в виде списка смежности, вставляя направленные ребра в обоих направлениях, чтобы симулировать неориентированные ребра.
Для определения, в какой компоненте связности находится каждый узел, мы выполняем обходы графа от произвольных непосещенных узлов до тех пор, пока все узлы не будут посещены. Для эффективности мы храним посещенные узлы в множестве (Set), что позволяет проводить проверки на принадлежность и вставку за константное время.
Наконец, мы рассматриваем каждую связную компоненту, объединяя все её интервалы, создавая новый интервал с началом, равным минимальному началу среди всех интервалов в компоненте, и концом, равным максимальному концу.
Решение:
import java.util.*;
class Solution {
private Map<int[], List<int[]>> graph;
private Map<Integer, List<int[]>> nodesInComp;
private Set<int[]> visited;
private boolean overlap(int[] a, int[] b) {
return a[0] <= b[1] && b[0] <= a[1];
}
private void buildGraph(int[][] intervals) {
graph = new HashMap<>();
for (int[] interval : intervals) {
graph.put(interval, new LinkedList<>());
}
for (int[] interval1 : intervals) {
for (int[] interval2 : intervals) {
if (overlap(interval1, interval2)) {
graph.get(interval1).add(interval2);
graph.get(interval2).add(interval1);
}
}
}
}
private int[] mergeNodes(List<int[]> nodes) {
int minStart = nodes.get(0)[0];
for (int[] node : nodes) {
minStart = Math.min(minStart, node[0]);
}
int maxEnd = nodes.get(0)[1];
for (int[] node : nodes) {
maxEnd = Math.max(maxEnd, node[1]);
}
return new int[] { minStart, maxEnd };
}
private void markComponentDFS(int[] start, int compNumber) {
Stack<int[]> stack = new Stack<>();
stack.add(start);
while (!stack.isEmpty()) {
int[] node = stack.pop();
if (!visited.contains(node)) {
visited.add(node);
if (nodesInComp.get(compNumber) == null) {
nodesInComp.put(compNumber, new LinkedList<>());
}
nodesInComp.get(compNumber).add(node);
for (int[] child : graph.get(node)) {
stack.add(child);
}
}
}
}
private void buildComponents(int[][] intervals) {
nodesInComp = new HashMap<>();
visited = new HashSet<>();
int compNumber = 0;
for (int[] interval : intervals) {
if (!visited.contains(interval)) {
markComponentDFS(interval, compNumber);
compNumber++;
}
}
}
public int[][] merge(int[][] intervals) {
buildGraph(intervals);
buildComponents(intervals);
List<int[]> merged = new LinkedList<>();
for (int comp = 0; comp < nodesInComp.size(); comp++) {
merged.add(mergeNodes(nodesInComp.get(comp)));
}
return merged.toArray(new int[merged.size()][]);
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
Задача: 1315. Sum of Nodes with Even-Valued Grandparent
Сложность: medium
Given the root of a binary tree, return the sum of values of nodes with an even-valued grandparent. If there are no nodes with an even-valued grandparent, return 0.
A grandparent of a node is the parent of its parent if it exists.
Пример:
👨💻 Алгоритм:
1⃣ Определите метод solve(), который принимает TreeNode root, значение родителя parent и значение бабушки или дедушки gParent. Этот метод возвращает сумму значений узлов с четным значением бабушки и дедушки в поддереве узла root. Если root равен null, верните 0 как сумму.
2⃣ Рекурсивно пройдите по левому и правому дочерним узлам, передавая в качестве значения parent root, а в качестве значения gParent parent. Если значение gParent четное, добавьте значение root к ответу.
3⃣ Вызовите рекурсивную функцию solve() с корневым узлом и значениями -1 для parent и gParent. Верните сумму для левого и правого дочерних узлов и значение для текущего узла.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Given the root of a binary tree, return the sum of values of nodes with an even-valued grandparent. If there are no nodes with an even-valued grandparent, return 0.
A grandparent of a node is the parent of its parent if it exists.
Пример:
Input: root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
Output: 18
Explanation: The red nodes are the nodes with even-value grandparent while the blue nodes are the even-value grandparents.
class Solution {
int solve(TreeNode root, int parent, int gParent) {
if (root == null) {
return 0;
}
return solve(root.left, root.val, parent) + solve(root.right, root.val, parent) + (gParent % 2 != 0 ? 0 : root.val);
}
public int sumEvenGrandparent(TreeNode root) {
return solve(root, -1, -1);
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 329. Longest Increasing Path in a Matrix
Сложность: hard
Дана матрица целых чисел размером m x n. Верните длину самого длинного возрастающего пути в матрице.
Из каждой ячейки можно перемещаться в четырех направлениях: влево, вправо, вверх или вниз. Перемещение по диагонали или выход за границы матрицы (т.е. замкнутые переходы) не допускается.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и создание матрицы:
Инициализируйте размеры матрицы m и n. Создайте матрицу matrix с добавленными границами (нулевыми значениями) вокруг исходной матрицы, чтобы избежать выхода за пределы при обработке.
Рассчитайте количество исходящих связей (outdegrees) для каждой клетки и сохраните их в outdegree.
2⃣ Поиск начальных листьев:
Найдите все клетки с нулевыми исходящими связями и добавьте их в список leaves. Эти клетки будут начальной точкой для "слоевого удаления".
3⃣ Удаление слоев:
Повторяйте процесс удаления клеток уровня за уровнем в порядке топологической сортировки, пока не останется листьев. Обновляйте количество исходящих связей и добавляйте новые листья на следующем уровне. Подсчитывайте количество уровней, что в итоге даст длину самого длинного возрастающего пути.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана матрица целых чисел размером m x n. Верните длину самого длинного возрастающего пути в матрице.
Из каждой ячейки можно перемещаться в четырех направлениях: влево, вправо, вверх или вниз. Перемещение по диагонали или выход за границы матрицы (т.е. замкнутые переходы) не допускается.
Пример:
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].
Инициализируйте размеры матрицы m и n. Создайте матрицу matrix с добавленными границами (нулевыми значениями) вокруг исходной матрицы, чтобы избежать выхода за пределы при обработке.
Рассчитайте количество исходящих связей (outdegrees) для каждой клетки и сохраните их в outdegree.
Найдите все клетки с нулевыми исходящими связями и добавьте их в список leaves. Эти клетки будут начальной точкой для "слоевого удаления".
Повторяйте процесс удаления клеток уровня за уровнем в порядке топологической сортировки, пока не останется листьев. Обновляйте количество исходящих связей и добавляйте новые листья на следующем уровне. Подсчитывайте количество уровней, что в итоге даст длину самого длинного возрастающего пути.
public class Solution {
private static final int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
private int m, n;
public int longestIncreasingPath(int[][] grid) {
int m = grid.length;
if (m == 0) return 0;
int n = grid[0].length;
int[][] matrix = new int[m + 2][n + 2];
for (int i = 0; i < m; ++i)
System.arraycopy(grid[i], 0, matrix[i + 1], 1, n);
int[][] outdegree = new int[m + 2][n + 2];
for (int i = 1; i <= m; ++i)
for (int j = 1; j <= n; ++j)
for (int[] d: dir)
if (matrix[i][j] < matrix[i + d[0]][j + d[1]])
outdegree[i][j]++;
n += 2;
m += 2;
List<int[]> leaves = new ArrayList<>();
for (int i = 1; i < m - 1; ++i)
for (int j = 1; j < n - 1; ++j)
if (outdegree[i][j] == 0) leaves.add(new int[]{i, j});
int height = 0;
while (!leaves.isEmpty()) {
height++;
List<int[]> newLeaves = new ArrayList<>();
for (int[] node : leaves) {
for (int[] d:dir) {
int x = node[0] + d[0], y = node[1] + d[1];
if (matrix[node[0]][node[1]] > matrix[x][y])
if (--outdegree[x][y] == 0)
newLeaves.add(new int[]{x, y});
}
}
leaves = newLeaves;
}
return height;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤔1
Задача: 477. Total Hamming Distance
Сложность: medium
Хэммингово расстояние между двумя целыми числами — это количество позиций, в которых соответствующие биты отличаются.
Дан целочисленный массив nums, верните сумму Хэмминговых расстояний между всеми парами чисел в nums.
Пример:
👨💻 Алгоритм:
1⃣ Для каждой уникальной пары элементов из массива вычисляем битовое XOR, чтобы найти позиции, где биты различаются. Бит, равный 1 в результате, указывает на различие.
2⃣ Для каждой пары элементов используем XOR, чтобы получить битовую разницу, и подсчитываем количество битов, равных 1, чтобы определить Хэммингово расстояние между парой.
3⃣ Суммируем все Хэмминговы расстояния для всех пар, чтобы получить общую сумму Хэмминговых расстояний.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Хэммингово расстояние между двумя целыми числами — это количество позиций, в которых соответствующие биты отличаются.
Дан целочисленный массив nums, верните сумму Хэмминговых расстояний между всеми парами чисел в nums.
Пример:
Input: nums = [4,14,2]
Output: 6
Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just
showing the four bits relevant in this case).
The answer will be:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.
public class Solution {
public int totalHammingDistance(int[] nums) {
int ans = 0;
if (nums.length == 0) {
return ans;
}
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i + 1; j < nums.length; j++) {
ans += Integer.bitCount(nums[i] ^ nums[j]);
}
}
return ans;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 999. Available Captures for Rook
Сложность: easy
Вам дана матрица 8 x 8, изображающая шахматную доску. На ней есть ровно одна белая ладья, представленная символом "R", некоторое количество белых слонов "B" и некоторое количество черных пешек "p". Пустые клетки обозначаются символом '.'. Ладья может перемещаться на любое количество клеток по горизонтали или вертикали (вверх, вниз, влево, вправо), пока не достигнет другой фигуры или края доски. Ладья атакует пешку, если она может переместиться на ее клетку за один ход. Примечание: Ладья не может перемещаться через другие фигуры, такие как слоны или пешки. Это означает, что ладья не может атаковать пешку, если путь ей преграждает другая фигура. Верните количество пешек, которые атакует белая ладья.
Пример:
👨💻 Алгоритм:
1⃣ Поиск ладьи:
Найдите координаты белой ладьи "R" на шахматной доске.
2⃣ Проверка направлений атаки:
Проверьте все четыре направления (влево, вправо, вверх, вниз) от позиции ладьи.
Перемещайтесь по каждому направлению до тех пор, пока не встретите другую фигуру или край доски.
3⃣ Подсчет атакованных пешек:
Если встреченная фигура - черная пешка "p", увеличьте счетчик атакованных пешек.
Если встреченная фигура - белый слон "B" или край доски, остановитесь в этом направлении.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дана матрица 8 x 8, изображающая шахматную доску. На ней есть ровно одна белая ладья, представленная символом "R", некоторое количество белых слонов "B" и некоторое количество черных пешек "p". Пустые клетки обозначаются символом '.'. Ладья может перемещаться на любое количество клеток по горизонтали или вертикали (вверх, вниз, влево, вправо), пока не достигнет другой фигуры или края доски. Ладья атакует пешку, если она может переместиться на ее клетку за один ход. Примечание: Ладья не может перемещаться через другие фигуры, такие как слоны или пешки. Это означает, что ладья не может атаковать пешку, если путь ей преграждает другая фигура. Верните количество пешек, которые атакует белая ладья.
Пример:
Input: board = [[".",".",".",".",".",".",".","."],[".",".",".","p",".",".",".","."],[".",".",".","R",".",".",".","p"],[".",".",".",".",".",".",".","."],[".",".",".",".",".",".",".","."],[".",".",".","p",".",".",".","."],[".",".",".",".",".",".",".","."],[".",".",".",".",".",".",".","."]]
Output: 3
Найдите координаты белой ладьи "R" на шахматной доске.
Проверьте все четыре направления (влево, вправо, вверх, вниз) от позиции ладьи.
Перемещайтесь по каждому направлению до тех пор, пока не встретите другую фигуру или край доски.
Если встреченная фигура - черная пешка "p", увеличьте счетчик атакованных пешек.
Если встреченная фигура - белый слон "B" или край доски, остановитесь в этом направлении.
public class Solution {
public int numRookCaptures(char[][] board) {
int countPawns(int x, int y, int dx, int dy) {
while (x >= 0 && x < 8 && y >= 0 && y < 8) {
if (board[x][y] == 'B') break;
if (board[x][y] == 'p') return 1;
x += dx;
y += dy;
}
return 0;
}
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (board[i][j] == 'R') {
return countPawns(i, j, -1, 0) + countPawns(i, j, 1, 0) +
countPawns(i, j, 0, -1) + countPawns(i, j, 0, 1);
}
}
}
return 0;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 314. Binary Tree Vertical Order Traversal
Сложность: medium
Дан корень бинарного дерева, верните вертикальный порядок обхода значений его узлов (т.е. сверху вниз, столбец за столбцом).
Если два узла находятся в одной строке и столбце, порядок должен быть слева направо.
Пример:
👨💻 Алгоритм:
1⃣ Создайте хэш-таблицу с именем columnTable для отслеживания результатов.
2⃣ Инициализируйте очередь, поместив в нее корневой узел вместе с его индексом столбца (0). Выполните обход в ширину (BFS), извлекая элементы из очереди. На каждой итерации извлекайте элемент, состоящий из узла и соответствующего индекса столбца. Если узел не пуст, добавьте его значение в columnTable. Затем поместите дочерние узлы с их индексами столбцов (т.е. column-1 и column+1) в очередь.
3⃣ После завершения BFS обхода получите хэш-таблицу, содержащую значения узлов, сгруппированные по индексам столбцов. Для каждой группы значений отсортируйте их по индексам строк. Отсортируйте хэш-таблицу по ключам (индексам столбцов) в порядке возрастания и верните результаты по столбцам.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева, верните вертикальный порядок обхода значений его узлов (т.е. сверху вниз, столбец за столбцом).
Если два узла находятся в одной строке и столбце, порядок должен быть слева направо.
Пример:
Input: root = [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
import java.util.*;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public List<List<Integer>> verticalOrder(TreeNode root) {
List<List<Integer>> output = new ArrayList<>();
if (root == null) {
return output;
}
Map<Integer, ArrayList<Integer>> columnTable = new HashMap<>();
Queue<Pair<TreeNode, Integer>> queue = new ArrayDeque<>();
int column = 0;
queue.offer(new Pair<>(root, column));
while (!queue.isEmpty()) {
Pair<TreeNode, Integer> p = queue.poll();
root = p.getKey();
column = p.getValue();
if (root != null) {
if (!columnTable.containsKey(column)) {
columnTable.put(column, new ArrayList<Integer>());
}
columnTable.get(column).add(root.val);
queue.offer(new Pair<>(root.left, column - 1));
queue.offer(new Pair<>(root.right, column + 1));
}
}
List<Integer> sortedKeys = new ArrayList<>(columnTable.keySet());
Collections.sort(sortedKeys);
for (int k : sortedKeys) {
output.add(columnTable.get(k));
}
return output;
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 173. Binary Search Tree Iterator
Сложность: medium
Реализуйте класс BSTIterator, который представляет итератор по обходу бинарного дерева поиска (BST) в порядке in-order:
BSTIterator(TreeNode root): Инициализирует объект класса BSTIterator. Корень BST передается в качестве параметра конструктора. Указатель должен быть инициализирован на несуществующее число, меньшее любого элемента в BST.
boolean hasNext(): Возвращает true, если в обходе справа от указателя существует число, иначе возвращает false.
int next(): Перемещает указатель вправо, затем возвращает число на указателе.
Обратите внимание, что при инициализации указателя на несуществующее наименьшее число, первый вызов next() вернет наименьший элемент в BST.
Можно предположить, что вызовы next() всегда будут допустимы. То есть, при вызове next() в обходе всегда будет хотя бы одно следующее число.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте пустой массив, который будет содержать узлы бинарного дерева поиска в отсортированном порядке.
2⃣ Мы обходим бинарное дерево поиска в порядке in-order и для каждого узла, который обрабатываем, добавляем его в наш массив узлов. Обратите внимание, что перед обработкой узла сначала нужно обработать (или рекурсивно вызвать) его левое поддерево, а после обработки узла — его правое поддерево.
3⃣ Когда у нас будут все узлы в массиве, нам просто нужен укзатель или индекс в этом массиве для реализации двух функций
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Реализуйте класс BSTIterator, который представляет итератор по обходу бинарного дерева поиска (BST) в порядке in-order:
BSTIterator(TreeNode root): Инициализирует объект класса BSTIterator. Корень BST передается в качестве параметра конструктора. Указатель должен быть инициализирован на несуществующее число, меньшее любого элемента в BST.
boolean hasNext(): Возвращает true, если в обходе справа от указателя существует число, иначе возвращает false.
int next(): Перемещает указатель вправо, затем возвращает число на указателе.
Обратите внимание, что при инициализации указателя на несуществующее наименьшее число, первый вызов next() вернет наименьший элемент в BST.
Можно предположить, что вызовы next() всегда будут допустимы. То есть, при вызове next() в обходе всегда будет хотя бы одно следующее число.
Пример:
Input
["BSTIterator", "next", "next", "hasNext", "next", "hasNext", "next", "hasNext", "next", "hasNext"]
[[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []]
Output
[null, 3, 7, true, 9, true, 15, true, 20, false]
Explanation
BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]);
bSTIterator.next(); // return 3
bSTIterator.next(); // return 7
bSTIterator.hasNext(); // return True
bSTIterator.next(); // return 9
bSTIterator.hasNext(); // return True
bSTIterator.next(); // return 15
bSTIterator.hasNext(); // return True
bSTIterator.next(); // return 20
bSTIterator.hasNext(); // return False
next и hasNext. Всякий раз, когда вызывается hasNext, мы просто проверяем, достиг ли индекс конца массива или нет. При вызове функции next мы просто возвращаем элемент, на который указывает индекс. Также, после вызова функции next, мы должны переместить индекс на один шаг вперед, чтобы имитировать прогресс нашего итератора.class BSTIterator {
ArrayList<Integer> nodesSorted;
int index;
public BSTIterator(TreeNode root) {
this.nodesSorted = new ArrayList<Integer>();
this.index = -1;
this._inorder(root);
}
private void _inorder(TreeNode root) {
if (root == null) {
return;
}
this._inorder(root.left);
this.nodesSorted.add(root.val);
this._inorder(root.right);
}
public int next() {
return this.nodesSorted.get(++this.index);
}
public boolean hasNext() {
return this.index + 1 < this.nodesSorted.size();
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1240. Tiling a Rectangle with the Fewest Squares
Сложность: hard
Если задан прямоугольник размером n x m, верните минимальное количество квадратов с целочисленными сторонами, которые покрывают этот прямоугольник.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация рекурсивной функции:
Функция принимает размеры прямоугольника n x m.
2⃣ Базовый случай:
Если n = 0 или m = 0, возвращаем 0, так как не осталось пространства для покрытия.
3⃣ Рекурсивный случай:
Находим наибольший возможный квадрат, который может быть размещен в текущем прямоугольнике. Это квадрат со стороной min(n, m).
Размещаем этот квадрат в левом верхнем углу и рекурсивно покрываем оставшиеся три части:
Прямоугольник слева от квадрата.
Прямоугольник сверху от квадрата.
Прямоугольник справа и снизу от квадрата.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Если задан прямоугольник размером n x m, верните минимальное количество квадратов с целочисленными сторонами, которые покрывают этот прямоугольник.
Пример:
Input: n = 2, m = 3
Output: 3
Функция принимает размеры прямоугольника n x m.
Если n = 0 или m = 0, возвращаем 0, так как не осталось пространства для покрытия.
Находим наибольший возможный квадрат, который может быть размещен в текущем прямоугольнике. Это квадрат со стороной min(n, m).
Размещаем этот квадрат в левом верхнем углу и рекурсивно покрываем оставшиеся три части:
Прямоугольник слева от квадрата.
Прямоугольник сверху от квадрата.
Прямоугольник справа и снизу от квадрата.
public class Solution {
public int tilingRectangle(int n, int m) {
int[][] dp = new int[n + 1][m + 1];
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= m; ++j) {
dp[i][j] = Integer.MAX_VALUE;
}
}
for (int i = 1; i <= Math.min(n, m); ++i) {
dp[i][i] = 1;
}
for (int h = 1; h <= n; ++h) {
for (int w = 1; w <= m; ++w) {
if (h == w) continue;
for (int i = 1; i <= h / 2; ++i) {
dp[h][w] = Math.min(dp[h][w], dp[i][w] + dp[h - i][w]);
}
for (int j = 1; j <= w / 2; ++j) {
dp[h][w] = Math.min(dp[h][w], dp[h][j] + dp[h][w - j]);
}
}
}
return dp[n][m];
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 286. Walls and Gates
Сложность: medium
Вам дана сетка размером m x n, представляющая комнаты, инициализированные следующими значениями:
-1: Стена или препятствие.
0: Ворота.
INF: Бесконечность, обозначающая пустую комнату. Мы используем значение 2^31 - 1 = 2147483647 для представления INF, так как можно предположить, что расстояние до ворот меньше 2147483647.
Заполните каждую пустую комнату расстоянием до ближайших ворот. Если невозможно добраться до ворот, комната должна быть заполнена значением INF.
Пример:
👨💻 Алгоритм:
1⃣ Обход всех комнат:
Пройдите через каждую клетку сетки, инициализируя очередь для BFS. Если клетка содержит ворота (0), добавьте её в очередь.
2⃣ BFS для поиска кратчайшего пути:
Используйте BFS для распространения из каждого ворот в соседние пустые комнаты. Обновите значение расстояния до ближайших ворот для каждой комнаты, которую вы посещаете, если это расстояние меньше текущего значения.
3⃣ Проверка всех направлений:
Для каждой клетки проверьте все возможные направления (вверх, вниз, влево, вправо) и добавляйте в очередь те, которые являются пустыми комнатами.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана сетка размером m x n, представляющая комнаты, инициализированные следующими значениями:
-1: Стена или препятствие.
0: Ворота.
INF: Бесконечность, обозначающая пустую комнату. Мы используем значение 2^31 - 1 = 2147483647 для представления INF, так как можно предположить, что расстояние до ворот меньше 2147483647.
Заполните каждую пустую комнату расстоянием до ближайших ворот. Если невозможно добраться до ворот, комната должна быть заполнена значением INF.
Пример:
Input: rooms = [[2147483647,-1,0,2147483647],[2147483647,2147483647,2147483647,-1],[2147483647,-1,2147483647,-1],[0,-1,2147483647,2147483647]]
Output: [[3,-1,0,1],[2,2,1,-1],[1,-1,2,-1],[0,-1,3,4]]
Пройдите через каждую клетку сетки, инициализируя очередь для BFS. Если клетка содержит ворота (0), добавьте её в очередь.
Используйте BFS для распространения из каждого ворот в соседние пустые комнаты. Обновите значение расстояния до ближайших ворот для каждой комнаты, которую вы посещаете, если это расстояние меньше текущего значения.
Для каждой клетки проверьте все возможные направления (вверх, вниз, влево, вправо) и добавляйте в очередь те, которые являются пустыми комнатами.
import java.util.LinkedList;
import java.util.Queue;
public class Solution {
private static final int INF = 2147483647;
private static final int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public void wallsAndGates(int[][] rooms) {
int m = rooms.length;
if (m == 0) return;
int n = rooms[0].length;
Queue<int[]> queue = new LinkedList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (rooms[i][j] == 0) {
queue.add(new int[]{i, j});
}
}
}
while (!queue.isEmpty()) {
int[] point = queue.poll();
int x = point[0], y = point[1];
for (int[] direction : directions) {
int nx = x + direction[0];
int ny = y + direction[1];
if (nx >= 0 && ny >= 0 && nx < m && ny < n && rooms[nx][ny] == INF) {
rooms[nx][ny] = rooms[x][y] + 1;
queue.add(new int[]{nx, ny});
}
}
}
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 847. Shortest Path Visiting All Nodes
Сложность: hard
У вас есть неориентированный связный граф из n узлов, пронумерованных от 0 до n - 1. Вам дан массив graph, где graph[i] — это список всех узлов, соединенных с узлом i ребром.
Верните длину кратчайшего пути, который посещает каждый узел. Вы можете начать и закончить в любом узле, вы можете несколько раз посещать узлы и использовать ребра повторно.
Пример:
👨💻 Алгоритм:
1⃣ Если граф содержит только один узел, верните 0, так как мы можем начать и закончить в этом узле, не делая никаких шагов.
2⃣ Инициализируйте необходимые переменные: количество узлов n, маску окончания endingMask, структуру данных seen для предотвращения циклов, очередь для выполнения BFS и счетчик шагов steps.
3⃣ Заполните очередь и seen начальными состояниями (начало в каждом узле с маской, указывающей, что посещен только данный узел), затем выполните BFS для поиска кратчайшего пути, который посещает все узлы. Если найден путь, возвращайте количество шагов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
У вас есть неориентированный связный граф из n узлов, пронумерованных от 0 до n - 1. Вам дан массив graph, где graph[i] — это список всех узлов, соединенных с узлом i ребром.
Верните длину кратчайшего пути, который посещает каждый узел. Вы можете начать и закончить в любом узле, вы можете несколько раз посещать узлы и использовать ребра повторно.
Пример:
Input: graph = [[1],[0,2,4],[1,3,4],[2],[1,2]]
Output: 4
Explanation: One possible path is [0,1,4,2,3]
class Solution {
public int shortestPathLength(int[][] graph) {
if (graph.length == 1) {
return 0;
}
int n = graph.length;
int endingMask = (1 << n) - 1;
boolean[][] seen = new boolean[n][endingMask];
ArrayList<int[]> queue = new ArrayList<>();
for (int i = 0; i < n; i++) {
queue.add(new int[] {i, 1 << i});
seen[i][1 << i] = true;
}
int steps = 0;
while (!queue.isEmpty()) {
ArrayList<int[]> nextQueue = new ArrayList<>();
for (int i = 0; i < queue.size(); i++) {
int[] currentPair = queue.get(i);
int node = currentPair[0];
int mask = currentPair[1];
for (int neighbor : graph[node]) {
int nextMask = mask | (1 << neighbor);
if (nextMask == endingMask) {
return 1 + steps;
}
if (!seen[neighbor][nextMask]) {
seen[neighbor][nextMask] = true;
nextQueue.add(new int[] {neighbor, nextMask});
}
}
}
steps++;
queue = nextQueue;
}
return -1;
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 711. Number of Distinct Islands II
Сложность: hard
Вам дана двоичная матричная сетка m x n. Остров - это группа 1 (представляющая сушу), соединенных в четырех направлениях (горизонтальном или вертикальном). Можно предположить, что все четыре края сетки окружены водой. Остров считается одинаковым с другим, если они имеют одинаковую форму, или имеют одинаковую форму после поворота (только на 90, 180 или 270 градусов) или отражения (влево/вправо или вверх/вниз). Верните количество разных островов.
Пример:
👨💻 Алгоритм:
1⃣ Пройдите по каждому элементу матрицы, если найдена земля (1), выполните DFS для обнаружения всех связанных с этим островом земель и сохраните форму острова.
2⃣ Нормализуйте форму острова, применив все возможные повороты и отражения, чтобы найти каноническую форму.
3⃣ Используйте множество для хранения всех уникальных канонических форм и верните размер этого множества.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Вам дана двоичная матричная сетка m x n. Остров - это группа 1 (представляющая сушу), соединенных в четырех направлениях (горизонтальном или вертикальном). Можно предположить, что все четыре края сетки окружены водой. Остров считается одинаковым с другим, если они имеют одинаковую форму, или имеют одинаковую форму после поворота (только на 90, 180 или 270 градусов) или отражения (влево/вправо или вверх/вниз). Верните количество разных островов.
Пример:
Input: grid = [[1,1,0,0,0],[1,0,0,0,0],[0,0,0,0,1],[0,0,0,1,1]]
Output: 1
import java.util.*;
public class Solution {
public int numDistinctIslands2(int[][] grid) {
Set<String> uniqueIslands = new HashSet<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
List<int[]> shape = new ArrayList<>();
dfs(grid, i, j, i, j, shape);
uniqueIslands.add(normalize(shape));
}
}
}
return uniqueIslands.size();
}
private void dfs(int[][] grid, int i, int j, int baseI, int baseJ, List<int[]> shape) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) {
return;
}
grid[i][j] = 0;
shape.add(new int[] {i - baseI, j - baseJ});
dfs(grid, i + 1, j, baseI, baseJ, shape);
dfs(grid, i - 1, j, baseI, baseJ, shape);
dfs(grid, i, j + 1, baseI, baseJ, shape);
dfs(grid, i, j - 1, baseI, baseJ, shape);
}
private String normalize(List<int[]> shape) {
List<List<int[]>> shapes = new ArrayList<>();
for (int i = 0; i < 8; i++) {
shapes.add(new ArrayList<>());
}
for (int[] point : shape) {
int x = point[0], y = point[1];
shapes.get(0).add(new int[] {x, y});
shapes.get(1).add(new int[] {x, -y});
shapes.get(2).add(new int[] {-x, y});
shapes.get(3).add(new int[] {-x, -y});
shapes.get(4).add(new int[] {y, x});
shapes.get(5).add(new int[] {y, -x});
shapes.get(6).add(new int[] {-y, x});
shapes.get(7).add(new int[] {-y, -x});
}
for (List<int[]> s : shapes) {
s.sort((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
}
String[] shapesStr = new String[8];
for (int i = 0; i < 8; i++) {
shapesStr[i] = shapes.get(i).toString();
}
Arrays.sort(shapesStr);
return shapesStr[0];
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM