Java | LeetCode
6.5K subscribers
219 photos
1 video
1.44K links
Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy

Контакт для рекламы: @easyoffer_adv
Download Telegram
Задача: 520. Detect Capital
Сложность: easy

Мы определяем правильное использование заглавных букв в слове, когда выполняется одно из следующих условий:

Все буквы в этом слове заглавные, как "USA".
Все буквы в этом слове строчные, как "leetcode".
Только первая буква в этом слове заглавная, как "Google".
Дана строка word. Верните true, если использование заглавных букв в ней правильное.

Пример:
Input: word = "USA"
Output: true


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

1⃣Шаблон для первого случая в регулярном выражении: [A-Z]*, где [A-Z] соответствует одной заглавной букве от 'A' до 'Z', а * означает повторение предыдущего шаблона 0 или более раз. Этот шаблон представляет "Все заглавные буквы".

2⃣Шаблон для второго случая в регулярном выражении: [a-z]*, где [a-z] соответствует одной строчной букве от 'a' до 'z'. Этот шаблон представляет "Все строчные буквы". Шаблон для третьего случая в регулярном выражении: [A-Z][a-z]*, где первая буква заглавная, а остальные строчные.

3⃣Объедините эти три шаблона: [A-Z]*|[a-z]*|[A-Z][a-z]*, где | означает "или". Мы можем объединить второй и третий случай, получив . [a-z]*, где . соответствует любому символу. Итоговый шаблон: [A-Z]*|.[a-z]*.

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

class Solution {
public boolean detectCapitalUse(String word) {
String pattern = "[A-Z]*|.[a-z]*";
return Pattern.matches(pattern, word);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 650. 2 Keys Keyboard
Сложность: medium

На экране блокнота есть только один символ 'A'. Для каждого шага можно выполнить одну из двух операций над этим блокнотом: Copy All: скопировать все символы, присутствующие на экране (частичное копирование не допускается). Paste: Вы можете вставить символы, которые были скопированы в прошлый раз. Учитывая целое число n, верните минимальное количество операций, чтобы символ 'A' появился на экране ровно n раз.

Пример:
Input: n = 3
Output: 3


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

1⃣Используйте динамическое программирование для отслеживания минимального количества операций, необходимых для достижения определенного количества 'A' на экране.

2⃣Итерируйтесь от 1 до n, проверяя все возможные делители текущего числа и обновляя минимальное количество операций для каждого числа.

3⃣Возвращайте значение из таблицы динамического программирования для n.

😎 Решение:
public class Solution {
public int minSteps(int n) {
if (n == 1) return 0;
int[] dp = new int[n + 1];
for (int i = 2; i <= n; i++) {
dp[i] = i;
for (int j = 1; j <= i / 2; j++) {
if (i % j == 0) {
dp[i] = Math.min(dp[i], dp[j] + i / j);
}
}
}
return dp[n];
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 867. Transpose Matrix
Сложность: easy

Дан двумерный целочисленный массив matrix, верните его транспонированную матрицу.

Транспонированная матрица — это матрица, перевернутая относительно своей главной диагонали, при этом строки и столбцы меняются местами.

Пример:
Input: matrix = [[1,2,3],[4,5,6],[7,8,9]]
Output: [[1,4,7],[2,5,8],[3,6,9]]


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

1⃣Инициализируйте новую матрицу ans с размерами C x R, где C — количество столбцов в исходной матрице, а R — количество строк.

2⃣Скопируйте каждую запись исходной матрицы в новую матрицу так, чтобы ans[c][r] = matrix[r][c].

3⃣Верните матрицу ans.

😎 Решение:
class Solution {
public int[][] transpose(int[][] A) {
int R = A.length, C = A[0].length;
int[][] ans = new int[C][R];
for (int r = 0; r < R; ++r)
for (int c = 0; c < C; ++c)
ans[c][r] = A[r][c];
return ans;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1249. Minimum Remove to Make Valid Parentheses
Сложность: medium

Дана строка s из '(' , ')' и строчных английских символов. Ваша задача - удалить минимальное количество скобок ( '(' или ')' в любых позициях), чтобы полученная строка со скобками была допустимой, и вернуть любую допустимую строку. Формально строка со скобками допустима тогда и только тогда, когда: она пустая, содержит только строчные символы, или может быть записана как AB (A, конкатенированная с B), где A и B - допустимые строки, или может быть записана как (A), где A - допустимая строка.

Пример:
Input: s = "lee(t(c)o)de)"
Output: "lee(t(c)o)de"


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

1⃣Пройдите по строке s и сохраните индексы всех открывающих скобок '(' в стек. При встрече закрывающей скобки ')', удалите соответствующую открытую скобку из стека. Если в стеке нет соответствующей открывающей скобки, пометьте эту закрывающую скобку для удаления.

2⃣После первого прохода, все оставшиеся в стеке открывающие скобки пометьте для удаления.

3⃣Создайте новую строку, удалив все помеченные скобки.

😎 Решение:
public class Solution {
public String minRemoveToMakeValid(String s) {
StringBuilder sb = new StringBuilder(s);
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < sb.length(); i++) {
if (sb.charAt(i) == '(') {
stack.push(i);
} else if (sb.charAt(i) == ')') {
if (!stack.isEmpty()) {
stack.pop();
} else {
sb.setCharAt(i, '*');
}
}
}
while (!stack.isEmpty()) {
sb.setCharAt(stack.pop(), '*');
}
return sb.toString().replaceAll("\\*", "");
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 913. Cat and Mouse
Сложность: hard

В игру на неориентированном графе играют два игрока, Мышь и Кот, которые чередуются по очереди. Граф задан следующим образом: graph[a] - это список всех вершин b, таких, что ab является ребром графа. Мышь начинает в вершине 1 и идет первой, Кот начинает в вершине 2 и идет второй, а в вершине 0 находится дыра. Во время хода каждого игрока он должен пройти по одному ребру графа, которое встречает его местоположение.Например, если Мышь находится в узле 1, она должна добраться до любого узла графа[1]. Кроме того, Кошке запрещено добираться до Дыры (узел 0). Затем игра может закончиться тремя способами: если Кошка занимает тот же узел, что и Мышь, Кошка побеждает. Если Мышь достигает Дыры, Мышь побеждает. Если позиция повторяется (т.е, игроки находятся в той же позиции, что и в предыдущий ход, и сейчас очередь того же игрока двигаться), то игра считается ничейной. Учитывая граф и предполагая, что оба игрока играют оптимально, верните 1, если в игре победила мышь, 2, если в игре победила кошка, или 0, если в игре ничья.

Пример:
Input: graph = [[2,5],[3],[0,4,5],[1,4,5],[2,3],[0,2,3]]
Output: 0


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

1⃣Использовать динамическое программирование с мемоизацией для хранения результатов игры для каждой комбинации позиций мыши, кота и текущего игрока.

2⃣Проверить три условия окончания игры:
Мышь достигает дырки (победа мыши).
Кот достигает мыши (победа кота).
Позиция повторяется (ничья).

3⃣Использовать BFS (поиск в ширину) для определения результатов игры, начиная с конечных состояний и работая назад.

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

public class Solution {
public int catMouseGame(int[][] graph) {
int n = graph.length;
final int DRAW = 0, MOUSE = 1, CAT = 2;
int[][][] dp = new int[n][n][2];
Queue<int[]> queue = new LinkedList<>();

for (int i = 1; i < n; i++) {
dp[0][i][0] = MOUSE;
dp[0][i][1] = MOUSE;
dp[i][i][0] = CAT;
dp[i][i][1] = CAT;
queue.offer(new int[]{0, i, 0, MOUSE});
queue.offer(new int[]{0, i, 1, MOUSE});
queue.offer(new int[]{i, i, 0, CAT});
queue.offer(new int[]{i, i, 1, CAT});
}

while (!queue.isEmpty()) {
int[] state = queue.poll();
int mouse = state[0], cat = state[1], turn = state[2], winner = state[3];
for (int[] parent : parents(graph, mouse, cat, turn)) {
int m = parent[0], c = parent[1], t = parent[2];
if (dp[m][c][t] == DRAW) {
if ((t == 0 && winner == MOUSE) || (t == 1 && winner == CAT)) {
dp[m][c][t] = winner;
queue.offer(new int[]{m, c, t, winner});
} else {
int degrees = 0;
for (int[] p : parents(graph, m, c, t)) degrees++;
if (degrees == 0) {
dp[m][c][t] = winner;
queue.offer(new int[]{m, c, t, winner});
}
}
}
}
}

return dp[1][2][0];
}

private List<int[]> parents(int[][] graph, int mouse, int cat, int turn) {
List<int[]> res = new ArrayList<>();
if (turn == 1) {
for (int m : graph[mouse]) {
res.add(new int[]{m, cat, 0});
}
} else {
for (int c : graph[cat]) {
if (c > 0) res.add(new int[]{mouse, c, 1});
}
}
return res;
}
}


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

Массив nums длины n красив, если: nums является перестановкой целых чисел в диапазоне [1, n]. Для каждого 0 <= i < j < n не существует индекса k с i < k < j, где 2 * nums[k] == nums[i] + nums[j]. Задано целое число n, верните любой красивый массив nums длины n. Для заданного n будет хотя бы один правильный ответ.

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


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

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

2⃣Если длина массива равна 1, вернуть массив [1].
Разделить n на четные и нечетные индексы и создать массивы для них.

3⃣Объединить массивы, созданные для четных и нечетных индексов, в результирующий массив.

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

class Solution {
public int[] beautifulArray(int n) {
List<Integer> result = construct(n);
int[] resArray = new int[result.size()];
for (int i = 0; i < result.size(); i++) {
resArray[i] = result.get(i);
}
return resArray;
}

private List<Integer> construct(int n) {
if (n == 1) {
List<Integer> base = new ArrayList<>();
base.add(1);
return base;
}
List<Integer> odd = construct((n + 1) / 2);
List<Integer> even = construct(n / 2);
List<Integer> result = new ArrayList<>();
for (int x : odd) {
result.add(2 * x - 1);
}
for (int x : even) {
result.add(2 * x);
}
return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 568. Maximum Vacation Days
Сложность: hard

LeetCode хочет предоставить одному из своих лучших сотрудников возможность путешествовать по n городам для сбора задач по алгоритмам. Однако, как говорится, "делу время, потехе час". Вы можете брать отпуска в некоторых конкретных городах и неделях. Ваша задача — спланировать поездку, чтобы максимально увеличить количество дней отпуска, которые вы сможете взять, соблюдая при этом определенные правила и ограничения.

Правила и ограничения:
Вы можете путешествовать только между n городами, обозначенными индексами от 0 до n-1. Изначально вы находитесь в городе с индексом 0 в понедельник.
Города связаны рейсами. Рейсы представлены матрицей n x n, называемой flights, представляющей статус авиалинии от города i до города j. Если рейса из города i в город j нет, flights[i][j] == 0; иначе flights[i][j] == 1. Также для всех i выполняется flights[i][i] == 0.
У вас есть k недель (каждая неделя состоит из семи дней) для путешествий. Вы можете летать не более одного раза в день и можете летать только утром каждого понедельника. Время полета настолько короткое, что его влияние не учитывается.
Для каждого города у вас есть ограниченные дни отпуска в разные недели, заданные матрицей n x k, называемой days. Значение days[i][j] представляет максимальное количество дней отпуска, которые вы можете взять в городе i на неделе j.
Даны две матрицы flights и days, верните максимальное количество дней отпуска, которые вы можете взять в течение k недель.

Пример:
Input: flights = [[0,1,1],[1,0,1],[1,1,0]], days = [[1,3,1],[6,0,3],[3,3,3]]
Output: 12
Explanation:
One of the best strategies is:
1st week : fly from city 0 to city 1 on Monday, and play 6 days and work 1 day.
(Although you start at city 0, we could also fly to and start at other cities since it is Monday.)
2nd week : fly from city 1 to city 2 on Monday, and play 3 days and work 4 days.
3rd week : stay at city 2, and play 3 days and work 4 days.
Ans = 6 + 3 + 3 = 12.


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

1⃣Использовать функцию dfs (поиск в глубину), которая возвращает количество отпускных дней, которые можно взять, начиная с текущего города cur_city и текущей недели weekno. В каждом вызове функции проходить по всем городам и находить все города, которые связаны с текущим городом. Такой город обозначен 1 в соответствующей позиции flights[cur_city][i].

2⃣Для текущего города можно либо остаться в нем, либо поехать в связанный город. Обозначим город, в который меняется расположение, как j. После смены города нужно найти количество отпускных дней, которые можно взять, начиная с нового города и с новой недели. Это количество отпускных дней можно представить как: days[j][weekno] + dfs(flights, days, j, weekno + 1).

3⃣Для текущего города необходимо найти максимальное количество отпускных дней, выбирая различные города в качестве следующего местоположения. Из всех вариантов отпускных дней выбираем максимальное значение, которое и будет возвращено для каждого вызова функции dfs.

😎 Решение:
public class Solution {
public int maxVacationDays(int[][] flights, int[][] days) {
int n = flights.length;
int k = days[0].length;
int[][] memo = new int[n][k];
for (int[] row : memo) {
Arrays.fill(row, -1);
}
return dfs(flights, days, memo, 0, 0);
}
private int dfs(int[][] flights, int[][] days, int[][] memo, int curCity, int weekNo) {
int n = flights.length;
int k = days[0].length;
if (weekNo == k) return 0;
if (memo[curCity][weekNo] != -1) return memo[curCity][weekNo];
int maxVac = 0;
for (int nextCity = 0; nextCity < n; nextCity++) {
if (curCity == nextCity || flights[curCity][nextCity] == 1) {
maxVac = Math.max(maxVac, days[nextCity][weekNo] + dfs(flights, days, memo, nextCity, weekNo + 1));
}
}
memo[curCity][weekNo] = maxVac;
return maxVac;
}
}


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

Дано целое число n, ваша задача состоит в том, чтобы посчитать, сколько строк длины n можно сформировать по следующим правилам:
Каждый символ является строчной гласной буквой ('a', 'e', 'i', 'o', 'u')
Каждая гласная 'a' может быть только перед 'e'.
Каждая гласная 'e' может быть только перед 'a' или 'i'.
Каждая гласная 'i' не может быть перед другой 'i'.
Каждая гласная 'o' может быть только перед 'i' или 'u'.
Каждая гласная 'u' может быть только перед 'a'.
Так как ответ может быть слишком большим, верните его по модулю 10^9 + 7.

Пример:
Input: n = 2
Output: 10
Explanation: All possible strings are: "ae", "ea", "ei", "ia", "ie", "io", "iu", "oi", "ou" and "ua".


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

1⃣Инициализация массивов и начальных условий:
Инициализируйте пять одномерных массивов размером n для хранения количества строк, оканчивающихся на каждую гласную.
Установите первый элемент в каждом массиве равным 1, так как для строк длиной 1 существует только одна возможная строка для каждой гласной.

2⃣Заполнение массивов в соответствии с правилами:
Проходите по длине строки от 1 до n.
Обновляйте значения массивов, следуя правилам для каждой гласной, учитывая предыдущие значения.

3⃣Суммирование и возврат результата:
Возьмите сумму последних элементов всех пяти массивов.
Верните результат по модулю 10^9 + 7.

😎 Решение:
class Solution {
public int countVowelPermutation(int n) {

long[] aVowelPermutationCount = new long[n];
long[] eVowelPermutationCount = new long[n];
long[] iVowelPermutationCount = new long[n];
long[] oVowelPermutationCount = new long[n];
long[] uVowelPermutationCount = new long[n];

aVowelPermutationCount[0] = 1L;
eVowelPermutationCount[0] = 1L;
iVowelPermutationCount[0] = 1L;
oVowelPermutationCount[0] = 1L;
uVowelPermutationCount[0] = 1L;

int MOD = 1000000007;

for (int i = 1; i < n; i++) {
aVowelPermutationCount[i] = (eVowelPermutationCount[i - 1] + iVowelPermutationCount[i - 1] + uVowelPermutationCount[i - 1]) % MOD;
eVowelPermutationCount[i] = (aVowelPermutationCount[i - 1] + iVowelPermutationCount[i - 1]) % MOD;
iVowelPermutationCount[i] = (eVowelPermutationCount[i - 1] + oVowelPermutationCount[i - 1]) % MOD;
oVowelPermutationCount[i] = iVowelPermutationCount[i - 1] % MOD;
uVowelPermutationCount[i] = (iVowelPermutationCount[i - 1] + oVowelPermutationCount[i - 1]) % MOD;
}

long result = 0L;

result = (aVowelPermutationCount[n - 1] + eVowelPermutationCount[n - 1] + iVowelPermutationCount[n - 1] + oVowelPermutationCount[n - 1] + uVowelPermutationCount[n - 1]) % MOD;

return (int)result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: №29. Divide Two Integers
Сложность: medium

Даны два целых числа dividend и divisor.
Выполните деление без использования операторов *, /, %.
Результат должен быть усечён до целого и находиться в пределах 32-битного целого числа.

Пример:
Input: dividend = 10, divisor = 3 Output: 3
Input: dividend = 7, divisor = -3 Output: -2


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

1⃣Определить знак результата и привести dividend и divisor к положительным значениям типа long, чтобы избежать переполнения и упростить работу с отрицательными числами.

2⃣Найти максимальное кратное делителя (удваивая divisor и счётчик divide), не превышающее dividend.

3⃣Рекурсивно вызвать деление для остатка dividend - sum, сложить с текущим divide и вернуть результат с учётом знака.

😎 Решение:
public class Solution {
public int divide(int dividend, int divisor) {
long result = divideLong(dividend, divisor);
return result > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)result;
}

private long divideLong(long dividend, long divisor) {
boolean negative = dividend < 0 != divisor < 0;

dividend = Math.abs(dividend);
divisor = Math.abs(divisor);

if (dividend < divisor) return 0;

long sum = divisor;
long divide = 1;
while ((sum + sum) <= dividend) {
sum += sum;
divide += divide;
}

long remaining = divideLong(dividend - sum, divisor);
return negative ? -(divide + remaining) : (divide + remaining);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1019. Next Greater Node In Linked List
Сложность: medium

Вам дана голова связного списка с n узлами. Для каждого узла в списке найдите значение следующего большего узла. То есть для каждого узла найдите значение первого узла, который находится рядом с ним и имеет строго большее значение, чем он. Верните целочисленный массив answer, где answer[i] - это значение следующего большего узла ith-узла (с индексацией по 1). Если у узла ith нет следующего большего узла, установите answer[i] = 0.

Пример:
Input: head = [2,1,5]
Output: [5,5,0]


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

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

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

3⃣Заполнение оставшихся значений:
Для всех индексов, оставшихся в стеке, установите значение ответа равным 0, так как для них не найдено большего элемента.

😎 Решение:
public class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}

public class Solution {
public int[] nextLargerNodes(ListNode head) {
List<Integer> values = new ArrayList<>();
while (head != null) {
values.add(head.val);
head = head.next;
}

int[] answer = new int[values.size()];
Stack<Integer> stack = new Stack<>();

for (int i = 0; i < values.size(); i++) {
while (!stack.isEmpty() && values.get(stack.peek()) < values.get(i)) {
answer[stack.pop()] = values.get(i);
}
stack.push(i);
}

return answer;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 826. Most Profit Assigning Work
Сложность: medium

У вас есть n заданий и m рабочих. Вам даны три массива: difficulty, profit и worker, где:
difficulty[i] и profit[i] — сложность и прибыль i-го задания,
worker[j] — способность j-го рабочего (т.е. j-й рабочий может выполнить задание со сложностью не больше worker[j]).
Каждому рабочему можно назначить не более одного задания, но одно задание может быть выполнено несколько раз.
Например, если три рабочих выполняют одно и то же задание с оплатой $1, общая прибыль составит $3. Если рабочий не может выполнить ни одно задание, его прибыль равна $0.

Верните максимальную прибыль, которую можно получить после распределения рабочих по заданиям.

Пример:
Input: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7]
Output: 100
Explanation: Workers are assigned jobs of difficulty [4,4,6,6] and they get a profit of [20,20,30,30] separately.


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

1⃣Создание и сортировка профиля работы
Инициализируйте массив пар jobProfile с {0, 0}. Для каждого задания добавьте {difficulty[i], profit[i]} в jobProfile. Отсортируйте jobProfile по возрастанию сложности.

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

3⃣Вычисление максимальной прибыли
Для каждой способности рабочего используйте бинарный поиск, чтобы найти задание с наибольшей прибылью, которую может выполнить этот рабочий. Суммируйте полученную прибыль для всех рабочих и верните ее.

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

public int maxProfitAssignment(
int[] difficulty,
int[] profit,
int[] worker
) {
List<int[]> jobProfile = new ArrayList<>();
jobProfile.add(new int[] { 0, 0 });
for (int i = 0; i < difficulty.length; i++) {
jobProfile.add(new int[] { difficulty[i], profit[i] });
}

Collections.sort(jobProfile, (a, b) -> Integer.compare(a[0], b[0]));
for (int i = 0; i < jobProfile.size() - 1; i++) {
jobProfile.get(i + 1)[1] = Math.max(
jobProfile.get(i)[1],
jobProfile.get(i + 1)[1]
);
}

int netProfit = 0;
for (int i = 0; i < worker.length; i++) {
int ability = worker[i];

int l = 0, r = jobProfile.size() - 1, jobProfit = 0;
while (l <= r) {
int mid = (l + r) / 2;
if (jobProfile.get(mid)[0] <= ability) {
jobProfit = Math.max(jobProfit, jobProfile.get(mid)[1]);
l = mid + 1;
} else {
r = mid - 1;
}
}

netProfit += jobProfit;
}
return netProfit;
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 922. Sort Array By Parity II
Сложность: medium

Дан массив целых чисел nums, половина целых чисел в нем нечетные, а другая половина - четные. Отсортируйте массив так, чтобы во всех случаях, когда nums[i] нечетный, i был нечетным, а во всех случаях, когда nums[i] четный, i был четным. Верните любой массив ответов, удовлетворяющий этому условию.

Пример:
Input: nums = [4,2,5,7]
Output: [4,5,2,7]


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

1⃣Инициализировать два указателя even_idx и odd_idx для отслеживания позиций четных и нечетных индексов соответственно.

2⃣Пройти по массиву nums и для каждого элемента:
Если элемент четный, поместить его на позицию even_idx и увеличить even_idx на 2.
Если элемент нечетный, поместить его на позицию odd_idx и увеличить odd_idx на 2.

3⃣Вернуть отсортированный массив.

😎 Решение:
class Solution {
public int[] sortArrayByParityII(int[] nums) {
int[] result = new int[nums.length];
int evenIdx = 0;
int oddIdx = 1;

for (int num : nums) {
if (num % 2 == 0) {
result[evenIdx] = num;
evenIdx += 2;
} else {
result[oddIdx] = num;
oddIdx += 2;
}
}

return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 172. Factorial Trailing Zeroes
Сложность: medium

Дано целое число n, верните количество конечных нулей в n!.

Обратите внимание, что n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1.

Пример:
Input: n = 3
Output: 0
Explanation: 3! = 6, no trailing zero.


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

1⃣Вычислите факториал n:
Инициализируйте переменную nFactorial значением 1.
Для каждого i от 2 до n включительно умножайте nFactorial на i.

2⃣Подсчитайте количество конечных нулей в nFactorial:
Инициализируйте переменную zeroCount значением 0.
Пока nFactorial делится на 10 без остатка, делите его на 10 и увеличивайте zeroCount на 1.

3⃣Верните значение zeroCount как количество конечных нулей в n!.

😎 Решение:
import java.math.BigInteger;

class Solution {
public int trailingZeroes(int n) {

BigInteger nFactorial = BigInteger.ONE;
for (int i = 2; i <= n; i++) {
nFactorial = nFactorial.multiply(BigInteger.valueOf(i));
}

int zeroCount = 0;

while (nFactorial.mod(BigInteger.TEN).equals(BigInteger.ZERO)) {
nFactorial = nFactorial.divide(BigInteger.TEN);
zeroCount++;
}

return zeroCount;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1329. Sort the Matrix Diagonally
Сложность: medium

Диагональ матрицы — это диагональная линия ячеек, начинающаяся с какой-либо ячейки в самой верхней строке или в самом левом столбце и идущая в направлении вниз-вправо до конца матрицы. Например, диагональ матрицы, начинающаяся с mat[2][0], где mat — это матрица размером 6 x 3, включает ячейки mat[2][0], mat[3][1] и mat[4][2].

Дана матрица mat размером m x n, состоящая из целых чисел. Отсортируйте каждую диагональ матрицы по возрастанию и верните полученную матрицу.

Пример:
Input: mat = [[3,3,1,1],[2,2,1,2],[1,1,1,2]]
Output: [[1,1,1,1],[1,2,2,2],[1,2,3,3]]


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

1⃣Сохраните размеры матрицы m и n. Создайте хеш-карту из минимальных куч для хранения элементов диагоналей.

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

3⃣Извлеките значения из хеш-карты и обновите матрицу, заполняя ее отсортированными значениями диагоналей. Верните отсортированную матрицу.

😎 Решение:
class Solution {
public int[][] diagonalSort(int[][] mat) {
int m = mat.length;
int n = mat[0].length;

Map<Integer, PriorityQueue<Integer>> diagonals = new HashMap<>();

for (int row = 0; row < m; row++) {
for (int col = 0; col < n; col++) {
int key = row - col;
diagonals.putIfAbsent(key, new PriorityQueue<>());
diagonals.get(key).add(mat[row][col]);
}
}

for (int row = 0; row < m; row++) {
for (int col = 0; col < n; col++) {
int key = row - col;
mat[row][col] = diagonals.get(key).poll();
}
}

return mat;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1277. Count Square Submatrices with All Ones
Сложность: medium

Если задана матрица m * n из единиц и нулей, верните, сколько квадратных подматриц имеют все единицы.

Пример:
Input: matrix =
[
[0,1,1,1],
[1,1,1,1],
[0,1,1,1]
]
Output: 15


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

1⃣Создайте вспомогательную матрицу dp таких же размеров, что и исходная матрица, для хранения размеров максимальных квадратов.

2⃣Пройдите по каждому элементу матрицы и обновите dp следующим образом: если элемент равен 1, то dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1.

3⃣Суммируйте все значения в dp, чтобы получить количество квадратных подматриц, состоящих из всех единиц.

😎 Решение:
public class Solution {
public int countSquares(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
int[][] dp = new int[m][n];
int count = 0;

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 1) {
if (i == 0 || j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = Math.min(dp[i-1][j], Math.min(dp[i][j-1], dp[i-1][j-1])) + 1;
}
count += dp[i][j];
}
}
}

return count;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1042. Flower Planting With No Adjacent
Сложность: medium

У вас есть n садов, помеченных от 1 до n, и массив paths, где paths[i] = [xi, yi] описывает двунаправленный путь между садом xi и садом yi. В каждом саду вы хотите посадить один из 4 типов цветов. Все сады имеют не более 3 путей, входящих и выходящих из него. Ваша задача - выбрать тип цветка для каждого сада так, чтобы для любых двух садов, соединенных путем, они имели разные типы цветов. Верните любой такой выбор в виде массива answer, где answer[i] - тип цветка, посаженного в (i+1)-м саду. Типы цветов обозначаются 1, 2, 3 или 4. Ответ гарантированно существует.

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


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

1⃣Построение графа:
Создайте граф из садов и путей между ними.

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

3⃣Мы будем проходить по каждому саду и выбирать тип цветка, который не совпадает с типами цветов в соседних садах. Поскольку у каждого сада не более трех соседей, всегда будет возможность выбрать тип цветка из 4 возможных типов.

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

public class Solution {
public int[] gardenNoAdj(int n, int[][] paths) {
List<Integer>[] graph = new ArrayList[n];
for (int i = 0; i < n; i++) {
graph[i] = new ArrayList<>();
}
for (int[] path : paths) {
graph[path[0] - 1].add(path[1] - 1);
graph[path[1] - 1].add(path[0] - 1);
}

int[] answer = new int[n];
for (int garden = 0; garden < n; garden++) {
boolean[] used = new boolean[5];
for (int neighbor : graph[garden]) {
used[answer[neighbor]] = true;
}
for (int flower = 1; flower <= 4; flower++) {
if (!used[flower]) {
answer[garden] = flower;
break;
}
}
}

return answer;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1198. Find Smallest Common Element in All Rows
Сложность: 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


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

1⃣Инициализация переменных:
Инициализируйте массив позиций pos, переменную для текущего максимального значения cur_max и счетчик cnt нулями.

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

3⃣Проверка счетчика:
Если счетчик равен количеству строк, возвращайте текущий максимум.
Повторите шаг 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;
}
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1424. Diagonal Traverse II
Сложность: medium

Дан двумерный целочисленный массив nums, верните все элементы nums в диагональном порядке.

Пример:
Input: nums = [[1,2,3,4,5],[6,7],[8],[9,10,11],[12,13,14,15,16]]
Output: [1,6,2,8,7,3,9,4,12,10,5,13,11,14,15,16]


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

1⃣Инициализируйте очередь с (0, 0) и список ответов ans.

2⃣Пока очередь не пуста:
Извлеките (row, col) из очереди.
Добавьте nums[row][col] в ans.
Если col == 0 и row + 1 в пределах массива, добавьте (row + 1, col) в очередь.
Если col + 1 в пределах текущей строки, добавьте (row, col + 1) в очередь.

3⃣Верните ans.

😎 Решение:
class Solution {
public int[] findDiagonalOrder(List<List<Integer>> nums) {
Queue<Pair<Integer, Integer>> queue = new LinkedList();
queue.offer(new Pair(0, 0));
List<Integer> ans = new ArrayList();

while (!queue.isEmpty()) {
Pair<Integer, Integer> p = queue.poll();
int row = p.getKey();
int col = p.getValue();
ans.add(nums.get(row).get(col));

if (col == 0 && row + 1 < nums.size()) {
queue.offer(new Pair(row + 1, col));
}

if (col + 1 < nums.get(row).size()) {
queue.offer(new Pair(row, col + 1));
}
}

int[] result = new int[ans.size()];
int i = 0;
for (int num : ans) {
result[i] = num;
i++;
}

return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 783. Minimum Distance Between BST Nodes
Сложность: easy

Дан корень дерева поиска (BST). Верните минимальную разницу между значениями любых двух различных узлов в дереве.

Пример:
Input: root = [4,2,6,1,3]
Output: 1


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

1⃣Инициализируйте minDistance значением MAX_VALUE; это переменная для хранения минимальной разницы.

2⃣Выполните обход дерева поиска в порядке возрастания (in-order traversal) и сохраните узлы в списке inorderNodes.

3⃣Итеративно проходите по списку inorderNodes, начиная с индекса 1. Для каждого элемента на позиции i найдите разницу с элементом на индексе i - 1 и соответствующим образом обновите переменную minDistance.
Верните minDistance.

😎 Решение:
class Solution {
List<Integer> inorderNodes = new ArrayList<>();

private void inorderTraversal(TreeNode root) {
if (root == null) return;

inorderTraversal(root.left);
inorderNodes.add(root.val);
inorderTraversal(root.right);
}

public int minDiffInBST(TreeNode root) {
inorderTraversal(root);

int minDistance = Integer.MAX_VALUE;
for (int i = 1; i < inorderNodes.size(); i++) {
minDistance = Math.min(minDistance, inorderNodes.get(i) - inorderNodes.get(i - 1));
}

return minDistance;
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍1
Задача: 782. Transform to Chessboard
Сложность: hard

Дана бинарная сетка размером n x n. В каждом ходе можно поменять местами любые две строки или любые два столбца.

Верните минимальное количество ходов, чтобы преобразовать сетку в шахматную доску. Если задача невыполнима, верните -1.

Шахматная доска — это доска, на которой ни один 0 и ни одна 1 не соприкасаются друг с другом по вертикали и горизонтали.

Пример:
Input: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
Output: 2
Explanation: One potential sequence of moves is shown.
The first move swaps the first and second column.
The second move swaps the second and third row.


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

1⃣Для каждого набора строк (и столбцов соответственно) убедитесь, что существует только 2 вида линий в правильных количествах, которые являются противоположностями друг друга.

2⃣Затем для каждой возможной идеальной трансформации этой линии найдите минимальное количество перестановок, чтобы преобразовать эту линию в её идеальную и добавьте это к ответу. Например, [0, 1, 1, 1, 0, 0] имеет два идеала [0, 1, 0, 1, 0, 1] или [1, 0, 1, 0, 1, 0]; но [0, 1, 1, 1, 0] имеет только один идеал [1, 0, 1, 0, 1].

3⃣В Java мы используем целые числа для представления строк как двоичных чисел. Мы проверяем количество различий с [1, 0, 1, 0, 1, 0, ...] с помощью побитового исключающего ИЛИ с 0b010101010101.....01 = 0x55555555. Чтобы убедиться, что мы не добавляем излишне большие элементы.

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

class Solution {
public int movesToChessboard(int[][] board) {
int N = board.length;
int ans = 0;

for (Map<int[], Integer> count : Arrays.asList(
getCount(board),
getCount(transpose(board))
)) {
if (count.size() != 2 || !count.values().containsAll(Arrays.asList(N / 2, (N + 1) / 2))) {
return -1;
}

Iterator<int[]> iterator = count.keySet().iterator();
int[] line1 = iterator.next();
int[] line2 = iterator.next();
if (!allOpposite(line1, line2)) {
return -1;
}

List<Integer> starts = N % 2 == 0 ? Arrays.asList(0, 1) : Arrays.asList(line1[0] * 2 > N ? 1 : 0);

int minSwaps = Integer.MAX_VALUE;
for (int start : starts) {
int swaps = 0;
for (int i = 0; i < N; i++) {
if ((line1[i] - i % 2) % 2 != 0) {
swaps++;
}
}
minSwaps = Math.min(minSwaps, swaps / 2);
}
ans += minSwaps;
}

return ans;
}

private Map<int[], Integer> getCount(int[][] board) {
Map<int[], Integer> count = new HashMap<>();
for (int[] row : board) {
count.put(row, count.getOrDefault(row, 0) + 1);
}
return count;
}

private int[][] transpose(int[][] board) {
int N = board.length;
int[][] transposed = new int[N][N];
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
transposed[j][i] = board[i][j];
}
}
return transposed;
}

private boolean allOpposite(int[] line1, int[] line2) {
for (int i = 0; i < line1.length; i++) {
if ((line1[i] ^ line2[i]) == 0) {
return false;
}
}
return true;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 846. Hand of Straights
Сложность: medium

У Алисы есть некоторое количество карт, и она хочет переставить карты в группы так, чтобы каждая группа была размером groupSize и состояла из groupSize последовательных карт.

Дан целочисленный массив hand, где hand[i] — это значение, написанное на i-й карте, и целое число groupSize. Верните true, если она может переставить карты, или false в противном случае.

Пример:
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]


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

1⃣Проверьте, делится ли длина массива hand на groupSize. Если нет, верните false.

2⃣Создайте карту cardCount для хранения количества каждой карты в массиве hand.

3⃣Итерируйте по массиву hand и обновляйте карту cardCount. Затем итерируйте снова для создания групп:
Найдите начальную карту startCard для потенциальной последовательности, уменьшая startCard, пока не найдёте карту, которая отсутствует в карте cardCount.
Попробуйте сформировать последовательность из groupSize карт, начиная с startCard. Если какая-либо карта в потенциальной последовательности отсутствует в карте cardCount, верните false.
Если последовательность можно сформировать, уменьшите количество каждой карты в последовательности в карте cardCount.

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

public boolean isNStraightHand(int[] hand, int groupSize) {
if (hand.length % groupSize != 0) {
return false;
}

HashMap<Integer, Integer> cardCount = new HashMap<>();
for (int card : hand) {
int count = cardCount.getOrDefault(card, 0);
cardCount.put(card, count + 1);
}

for (int card : hand) {
int startCard = card;
while (cardCount.getOrDefault(startCard - 1, 0) > 0) {
startCard--;
}

while (startCard <= card) {
while (cardCount.getOrDefault(startCard, 0) > 0) {
for (
int nextCard = startCard;
nextCard < startCard + groupSize;
nextCard++
) {
if (cardCount.getOrDefault(nextCard, 0) == 0) {
return false;
}
cardCount.put(nextCard, cardCount.get(nextCard) - 1);
}
}
startCard++;
}
}

return true;
}
}


Ставь 👍 и забирай 📚 Базу знаний