Задача: 1143. Longest Common Subsequence
Сложность: medium
Даны две строки text1 и text2. Верните длину их наибольшей общей подпоследовательности. Если общей подпоследовательности нет, верните 0.
Подпоследовательность строки — это новая строка, созданная из оригинальной строки путем удаления некоторых символов (может быть ни одного) без изменения относительного порядка оставшихся символов.
Например, "ace" является подпоследовательностью "abcde".
Общая подпоследовательность двух строк — это подпоследовательность, которая является общей для обеих строк.
Пример:
👨💻 Алгоритм:
1⃣Создайте двумерный массив memo для хранения промежуточных результатов, чтобы избежать повторных вычислений. Инициализируйте массив значением -1, чтобы указать, что эти ячейки еще не были рассчитаны.
2⃣Реализуйте рекурсивную функцию memoSolve, которая принимает два указателя на текущие позиции в text1 и text2 и возвращает длину наибольшей общей подпоследовательности для этих подстрок. Если текущие символы совпадают, добавьте 1 к результату рекурсивного вызова для следующих символов. Если не совпадают, найдите максимум между рекурсивными вызовами с измененными указателями.
3⃣Возвращайте значение memoSolve(0, 0), чтобы получить результат для всей строки.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны две строки text1 и text2. Верните длину их наибольшей общей подпоследовательности. Если общей подпоследовательности нет, верните 0.
Подпоследовательность строки — это новая строка, созданная из оригинальной строки путем удаления некоторых символов (может быть ни одного) без изменения относительного порядка оставшихся символов.
Например, "ace" является подпоследовательностью "abcde".
Общая подпоследовательность двух строк — это подпоследовательность, которая является общей для обеих строк.
Пример:
Input: text1 = "abcde", text2 = "ace"
Output: 3
Explanation: The longest common subsequence is "ace" and its length is 3.
👨💻 Алгоритм:
1⃣Создайте двумерный массив memo для хранения промежуточных результатов, чтобы избежать повторных вычислений. Инициализируйте массив значением -1, чтобы указать, что эти ячейки еще не были рассчитаны.
2⃣Реализуйте рекурсивную функцию memoSolve, которая принимает два указателя на текущие позиции в text1 и text2 и возвращает длину наибольшей общей подпоследовательности для этих подстрок. Если текущие символы совпадают, добавьте 1 к результату рекурсивного вызова для следующих символов. Если не совпадают, найдите максимум между рекурсивными вызовами с измененными указателями.
3⃣Возвращайте значение memoSolve(0, 0), чтобы получить результат для всей строки.
😎 Решение:
class Solution {
private int[][] memo;
private String text1;
private String text2;
public int longestCommonSubsequence(String text1, String text2) {
this.memo = new int[text1.length() + 1][text2.length() + 1];
for (int i = 0; i < text1.length(); i++) {
for (int j = 0; j < text2.length(); j++) {
this.memo[i][j] = -1;
}
}
this.text1 = text1;
this.text2 = text2;
return memoSolve(0, 0);
}
private int memoSolve(int p1, int p2) {
if (memo[p1][p2] != -1) {
return memo[p1][p2];
}
int answer = 0;
if (text1.charAt(p1) == text2.charAt(p2)) {
answer = 1 + memoSolve(p1 + 1, p2 + 1);
} else {
answer = Math.max(memoSolve(p1, p2 + 1), memoSolve(p1 + 1, p2));
}
memo[p1][p2] = answer;
return memo[p1][p2];
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 1379. Find a Corresponding Node of a Binary Tree in a Clone of That Tree
Сложность: easy
Даны два бинарных дерева: original и cloned, а также ссылка на узел target в оригинальном дереве.
Дерево cloned является копией оригинального дерева.
Верните ссылку на тот же узел в дереве cloned.
Обратите внимание, что вам не разрешается изменять какое-либо из двух деревьев или узел target, и ответ должен быть ссылкой на узел в дереве cloned.
Пример:
👨💻 Алгоритм:
1⃣Добавьте корень в очередь.
2⃣Пока очередь не пуста, извлекайте узел из очереди. Если узел является целевым, завершите выполнение. Добавьте сначала левый, затем правый дочерний узел в очередь.
3⃣Верните ссылку на найденный целевой узел.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Даны два бинарных дерева: original и cloned, а также ссылка на узел target в оригинальном дереве.
Дерево cloned является копией оригинального дерева.
Верните ссылку на тот же узел в дереве cloned.
Обратите внимание, что вам не разрешается изменять какое-либо из двух деревьев или узел target, и ответ должен быть ссылкой на узел в дереве cloned.
Пример:
Input: tree = [7,4,3,null,null,6,19], target = 3
Output: 3
Explanation: In all examples the original and cloned trees are shown. The target node is a green node from the original tree. The answer is the yellow node from the cloned tree.
👨💻 Алгоритм:
1⃣Добавьте корень в очередь.
2⃣Пока очередь не пуста, извлекайте узел из очереди. Если узел является целевым, завершите выполнение. Добавьте сначала левый, затем правый дочерний узел в очередь.
3⃣Верните ссылку на найденный целевой узел.
😎 Решение:
class Solution {
public final TreeNode getTargetCopy(final TreeNode original, final TreeNode cloned, final TreeNode target) {
Deque<TreeNode> queue_o = new ArrayDeque<>();
queue_o.offer(original);
Deque<TreeNode> queue_c = new ArrayDeque<>();
queue_c.offer(cloned);
while (!queue_o.isEmpty()) {
TreeNode node_o = queue_o.poll();
TreeNode node_c = queue_c.poll();
if (node_o == target) {
return node_c;
}
if (node_o.left != null) {
queue_o.offer(node_o.left);
queue_c.offer(node_c.left);
}
if (node_o.right != null) {
queue_o.offer(node_o.right);
queue_c.offer(node_c.right);
}
}
return null;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 670. Maximum Swap
Сложность: medium
Дано целое число num. Вы можете поменять местами две цифры не более одного раза, чтобы получить число с наибольшим значением.
Верните число с наибольшим значением, которое можно получить.
Пример:
👨💻 Алгоритм:
1⃣Сохраняем кандидатов как списки длины len(num). Для каждой пары позиций (i, j) выполняем обмен цифр, записываем кандидата, если он больше текущего ответа, затем возвращаем цифры обратно.
2⃣Проверяем, что не добавили ведущий ноль. Фактически, проверять это не нужно, так как изначальное число его не содержит.
3⃣Возвращаем максимальное значение из всех кандидатов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дано целое число num. Вы можете поменять местами две цифры не более одного раза, чтобы получить число с наибольшим значением.
Верните число с наибольшим значением, которое можно получить.
Пример:
Input: num = 2736
Output: 7236
Explanation: Swap the number 2 and the number 7.
👨💻 Алгоритм:
1⃣Сохраняем кандидатов как списки длины len(num). Для каждой пары позиций (i, j) выполняем обмен цифр, записываем кандидата, если он больше текущего ответа, затем возвращаем цифры обратно.
2⃣Проверяем, что не добавили ведущий ноль. Фактически, проверять это не нужно, так как изначальное число его не содержит.
3⃣Возвращаем максимальное значение из всех кандидатов.
😎 Решение:
class Solution {
public int maximumSwap(int num) {
char[] A = Integer.toString(num).toCharArray();
char[] ans = Arrays.copyOf(A, A.length);
for (int i = 0; i < A.length; i++) {
for (int j = i + 1; j < A.length; j++) {
char tmp = A[i];
A[i] = A[j];
A[j] = tmp;
for (int k = 0; k < A.length; k++) {
if (A[k] != ans[k]) {
if (A[k] > ans[k]) {
ans = Arrays.copyOf(A, A.length);
}
break;
}
}
A[j] = A[i];
A[i] = tmp;
}
}
return Integer.valueOf(new String(ans));
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 243. Shortest Word Distance
Сложность: easy
Дан массив строк
Пример:
👨💻 Алгоритм:
1⃣Начните с перебора всего массива для поиска первого слова. Каждый раз, когда вы находите встречу первого слова, запомните его позицию.
2⃣При каждом обнаружении первого слова переберите массив в поисках ближайшего вхождения второго слова, сохраняя позицию и сравнивая расстояние с предыдущими найденными.
3⃣Сохраняйте минимальное найденное расстояние между двумя словами и возвращайте его в качестве результата.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан массив строк
wordsDict и две разные строки, которые уже существуют в массиве: word1 и word2. Верните кратчайшее расстояние между этими двумя словами в списке.Пример:
Input: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "coding", word2 = "practice"
Output: 3
👨💻 Алгоритм:
1⃣Начните с перебора всего массива для поиска первого слова. Каждый раз, когда вы находите встречу первого слова, запомните его позицию.
2⃣При каждом обнаружении первого слова переберите массив в поисках ближайшего вхождения второго слова, сохраняя позицию и сравнивая расстояние с предыдущими найденными.
3⃣Сохраняйте минимальное найденное расстояние между двумя словами и возвращайте его в качестве результата.
😎 Решение:
class Solution {
public int shortestDistance(String[] words, String word1, String word2) {
int minDistance = words.length;
for (int i = 0; i < words.length; i++) {
if (words[i].equals(word1)) {
for (int j = 0; j < words.length; j++) {
if (words[j].equals(word2)) {
minDistance = Math.min(minDistance, Math.abs(i - j));
}
}
}
}
return minDistance;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 426. Convert Binary Search Tree to Sorted Doubly Linked List
Сложность: medium
Преобразуйте двоичное дерево поиска в отсортированный кольцевой двусвязный список на месте.
Вы можете считать, что указатели "влево" и "вправо" аналогичны указателям на предшественника и последователя в двусвязном списке. Для кольцевого двусвязного списка предшественник первого элемента является последним элементом, а последователь последнего элемента является первым элементом.
Мы хотим выполнить преобразование на месте. После преобразования левый указатель узла дерева должен указывать на его предшественника, а правый указатель должен указывать на его последователя. Вы должны вернуть указатель на самый маленький элемент списка.
Пример:
👨💻 Алгоритм:
1⃣Инициализируйте первые и последние узлы как null.
2⃣Вызовите стандартную вспомогательную рекурсивную функцию helper(root):
Если узел не равен null:
Вызовите рекурсию для левого поддерева helper(node.left).
Если последний узел не равен null, свяжите последний узел и текущий узел.
Иначе инициализируйте первый узел.
Пометьте текущий узел как последний: last = node.
Вызовите рекурсию для правого поддерева helper(node.right).
3⃣Свяжите первые и последние узлы, чтобы замкнуть кольцевой двусвязный список, затем верните первый узел.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Преобразуйте двоичное дерево поиска в отсортированный кольцевой двусвязный список на месте.
Вы можете считать, что указатели "влево" и "вправо" аналогичны указателям на предшественника и последователя в двусвязном списке. Для кольцевого двусвязного списка предшественник первого элемента является последним элементом, а последователь последнего элемента является первым элементом.
Мы хотим выполнить преобразование на месте. После преобразования левый указатель узла дерева должен указывать на его предшественника, а правый указатель должен указывать на его последователя. Вы должны вернуть указатель на самый маленький элемент списка.
Пример:
Input: root = [4,2,5,1,3]
Output: [1,2,3,4,5]
Explanation: The figure below shows the transformed BST. The solid line indicates the successor relationship, while the dashed line means the predecessor relationship.
👨💻 Алгоритм:
1⃣Инициализируйте первые и последние узлы как null.
2⃣Вызовите стандартную вспомогательную рекурсивную функцию helper(root):
Если узел не равен null:
Вызовите рекурсию для левого поддерева helper(node.left).
Если последний узел не равен null, свяжите последний узел и текущий узел.
Иначе инициализируйте первый узел.
Пометьте текущий узел как последний: last = node.
Вызовите рекурсию для правого поддерева helper(node.right).
3⃣Свяжите первые и последние узлы, чтобы замкнуть кольцевой двусвязный список, затем верните первый узел.
😎 Решение:
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right) {
val = _val;
left = _left;
right = _right;
}
}
class Solution {
private Node first = null;
private Node last = null;
public void helper(Node node) {
if (node != null) {
helper(node.left);
if (last != null) {
last.right = node;
node.left = last;
} else {
first = node;
}
last = node;
helper(node.right);
}
}
public Node treeToDoublyList(Node root) {
if (root == null) return null;
helper(root);
last.right = first;
first.left = last;
return first;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 207. Course Schedule
Сложность: medium
Всего у вас есть numCourses курсов, которые нужно пройти, пронумерованных от 0 до numCourses - 1. Вам дан массив prerequisites, где prerequisites[i] = [ai, bi] указывает на то, что вы должны сначала пройти курс bi, если хотите взять курс ai.
Например, пара [0, 1] указывает на то, что для прохождения курса 0 сначала нужно пройти курс 1.
Верните true, если вы можете завершить все курсы. В противном случае верните false.
Пример:
👨💻 Алгоритм:
1⃣Создайте массив indegree длины n, где indegree[x] хранит количество входящих рёбер в узел x. Создайте список смежности adj, в котором adj[x] содержит все узлы с входящим ребром от узла x, то есть соседей узла x. Создайте этот список смежности, итерируя prerequisites. Для каждого prerequisites добавьте ребро от prerequisites[1] к prerequisites[0] и увеличьте indegree prerequisites[0] на 1.
2⃣Инициализируйте очередь целых чисел q и начните алгоритм BFS, перемещаясь от листовых узлов к родительским узлам. Начните обход BFS, поместив все листовые узлы (indegree равное 0) в очередь. Создайте целочисленную переменную nodesVisited = 0 для подсчета количества посещенных узлов.
3⃣Пока очередь не пуста:
Извлеките первый узел из очереди.
Увеличьте nodesVisited на 1.
Для каждого соседа (узлы, которые имеют входящее ребро от узла) узла уменьшите indegree[neighbor] на 1, чтобы удалить ребро node -> neighbor.
Если indegree[neighbor] == 0, это означает, что neighbor ведет себя как листовой узел, поэтому добавьте neighbor в очередь.
Если количество посещенных узлов меньше общего количества узлов, то есть nodesVisited < n, верните false, так как должен быть цикл. В противном случае, если nodesVisited == numCourses, верните true. Можно сократить это до просто возвращения nodesVisited == numCourses.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Всего у вас есть numCourses курсов, которые нужно пройти, пронумерованных от 0 до numCourses - 1. Вам дан массив prerequisites, где prerequisites[i] = [ai, bi] указывает на то, что вы должны сначала пройти курс bi, если хотите взять курс ai.
Например, пара [0, 1] указывает на то, что для прохождения курса 0 сначала нужно пройти курс 1.
Верните true, если вы можете завершить все курсы. В противном случае верните false.
Пример:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
👨💻 Алгоритм:
1⃣Создайте массив indegree длины n, где indegree[x] хранит количество входящих рёбер в узел x. Создайте список смежности adj, в котором adj[x] содержит все узлы с входящим ребром от узла x, то есть соседей узла x. Создайте этот список смежности, итерируя prerequisites. Для каждого prerequisites добавьте ребро от prerequisites[1] к prerequisites[0] и увеличьте indegree prerequisites[0] на 1.
2⃣Инициализируйте очередь целых чисел q и начните алгоритм BFS, перемещаясь от листовых узлов к родительским узлам. Начните обход BFS, поместив все листовые узлы (indegree равное 0) в очередь. Создайте целочисленную переменную nodesVisited = 0 для подсчета количества посещенных узлов.
3⃣Пока очередь не пуста:
Извлеките первый узел из очереди.
Увеличьте nodesVisited на 1.
Для каждого соседа (узлы, которые имеют входящее ребро от узла) узла уменьшите indegree[neighbor] на 1, чтобы удалить ребро node -> neighbor.
Если indegree[neighbor] == 0, это означает, что neighbor ведет себя как листовой узел, поэтому добавьте neighbor в очередь.
Если количество посещенных узлов меньше общего количества узлов, то есть nodesVisited < n, верните false, так как должен быть цикл. В противном случае, если nodesVisited == numCourses, верните true. Можно сократить это до просто возвращения nodesVisited == numCourses.
😎 Решение:
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[] indegree = new int[numCourses];
List<List<Integer>> adj = new ArrayList<>(numCourses);
for (int i = 0; i < numCourses; i++) {
adj.add(new ArrayList<>());
}
for (int[] prerequisite : prerequisites) {
adj.get(prerequisite[1]).add(prerequisite[0]);
indegree[prerequisite[0]]++;
}
Queue<Integer> queue = new LinkedList<>();
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) {
queue.offer(i);
}
}
int nodesVisited = 0;
while (!queue.isEmpty()) {
int node = queue.poll();
nodesVisited++;
for (int neighbor : adj.get(node)) {
indegree[neighbor]--;
if (indegree[neighbor] == 0) {
queue.offer(neighbor);
}
}
}
return nodesVisited == numCourses;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 188. Best Time to Buy and Sell Stock IV
Сложность: hard
Дан массив целых чисел prices, где prices[i] - это цена данной акции в i-й день, и целое число k.
Найдите максимальную прибыль, которую вы можете получить. Вы можете завершить не более чем k транзакций, т.е. вы можете купить не более k раз и продать не более k раз.
Обратите внимание: Вы не можете участвовать в нескольких транзакциях одновременно (т.е., вы должны продать акцию, прежде чем снова купить).
Пример:
👨💻 Алгоритм:
1⃣Инициализация DP массива: Инициализируйте трехмерный массив dp, где dp[i][j][l] представляет максимальную прибыль на конец i-го дня с j оставшимися транзакциями и l акциями в портфеле. Начните с dp[0][0][0] = 0 (нет прибыли без акций и транзакций) и dp[0][1][1] = -prices[0] (покупка первой акции).
2⃣Вычисление переходов: Для каждого дня и каждого возможного количества транзакций вычислите возможные действия: держать акцию, не держать акцию, купить акцию, если j > 0, или продать акцию. Обновляйте dp с использованием:
dp[i][j][1] = max(dp[i−1][j][1], dp[i−1][j−1][0] - prices[i]) (максимум между удержанием акции и покупкой новой).
dp[i][j][0] = max(dp[i−1][j][0], dp[i−1][j][1] + prices[i]) (максимум между неудержанием акции и продажей).
3⃣Расчет результатов: По завершении всех дней, возвращайте максимальное значение dp[n-1][j][0] для всех j от 0 до k, что представляет максимальную прибыль без удержания акций на последний день. Обработайте специальный случай, когда 𝑘×2≥𝑛, чтобы избежать лишних расчетов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дан массив целых чисел prices, где prices[i] - это цена данной акции в i-й день, и целое число k.
Найдите максимальную прибыль, которую вы можете получить. Вы можете завершить не более чем k транзакций, т.е. вы можете купить не более k раз и продать не более k раз.
Обратите внимание: Вы не можете участвовать в нескольких транзакциях одновременно (т.е., вы должны продать акцию, прежде чем снова купить).
Пример:
Input: k = 2, prices = [2,4,1]
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
👨💻 Алгоритм:
1⃣Инициализация DP массива: Инициализируйте трехмерный массив dp, где dp[i][j][l] представляет максимальную прибыль на конец i-го дня с j оставшимися транзакциями и l акциями в портфеле. Начните с dp[0][0][0] = 0 (нет прибыли без акций и транзакций) и dp[0][1][1] = -prices[0] (покупка первой акции).
2⃣Вычисление переходов: Для каждого дня и каждого возможного количества транзакций вычислите возможные действия: держать акцию, не держать акцию, купить акцию, если j > 0, или продать акцию. Обновляйте dp с использованием:
dp[i][j][1] = max(dp[i−1][j][1], dp[i−1][j−1][0] - prices[i]) (максимум между удержанием акции и покупкой новой).
dp[i][j][0] = max(dp[i−1][j][0], dp[i−1][j][1] + prices[i]) (максимум между неудержанием акции и продажей).
3⃣Расчет результатов: По завершении всех дней, возвращайте максимальное значение dp[n-1][j][0] для всех j от 0 до k, что представляет максимальную прибыль без удержания акций на последний день. Обработайте специальный случай, когда 𝑘×2≥𝑛, чтобы избежать лишних расчетов.
😎 Решение:
public class Solution {
public int maxProfit(int k, int[] prices) {
int n = prices.length;
if (n <= 0 || k <= 0) {
return 0;
}
if (k * 2 >= n) {
int res = 0;
for (int i = 1; i < n; i++) {
res += Math.max(0, prices[i] - prices[i - 1]);
}
return res;
}
int[][][] dp = new int[n][k + 1][2];
for (int i = 0; i < n; i++) {
for (int j = 0; j <= k; j++) {
dp[i][j][0] = -1000000000;
dp[i][j][1] = -1000000000;
}
}
dp[0][0][0] = 0;
dp[0][1][1] = -prices[0];
for (int i = 1; i < n; i++) {
for (int j = 0; j <= k; j++) { dp[i][j][0] = Math.max(
dp[i - 1][j][0],
dp[i - 1][j][1] + prices[i]
);
if (j > 0) {
dp[i][j][1] = Math.max(
dp[i - 1][j][1],
dp[i - 1][j - 1][0] - prices[i]
);
}
}
}
int res = 0;
for (int j = 0; j <= k; j++) {
res = Math.max(res, dp[n - 1][j][0]);
}
return res;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 422. Valid Word Square
Сложность: easy
Дан массив строк words, верните true, если он образует правильный квадрат слов.
Последовательность строк образует правильный квадрат слов, если k-я строка и k-й столбец читаются одинаково, где 0 <= k < max(numRows, numColumns).
Пример:
👨💻 Алгоритм:
1⃣Инициализируйте переменные: cols для максимальной длины слов в массиве, rows для количества строк в массиве words, и пустой массив newWords для хранения новых слов, представленных каждым столбцом.
2⃣Итерация по массиву words, определение максимальной длины слова для cols, проверка, что количество строк равно количеству столбцов. Если условие не выполняется, возвращаем false.
3⃣Для каждого столбца col от 0 до cols - 1, формируем строку newWord из символов на позиции (row, col) для каждой строки. Сохраняем newWord в массиве newWords. В конце, если newWords и words равны, возвращаем true, иначе false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан массив строк words, верните true, если он образует правильный квадрат слов.
Последовательность строк образует правильный квадрат слов, если k-я строка и k-й столбец читаются одинаково, где 0 <= k < max(numRows, numColumns).
Пример:
Input: words = ["abcd","bnrt","crmy","dtye"]
Output: true
Explanation:
The 1st row and 1st column both read "abcd".
The 2nd row and 2nd column both read "bnrt".
The 3rd row and 3rd column both read "crmy".
The 4th row and 4th column both read "dtye".
Therefore, it is a valid word square.
👨💻 Алгоритм:
1⃣Инициализируйте переменные: cols для максимальной длины слов в массиве, rows для количества строк в массиве words, и пустой массив newWords для хранения новых слов, представленных каждым столбцом.
2⃣Итерация по массиву words, определение максимальной длины слова для cols, проверка, что количество строк равно количеству столбцов. Если условие не выполняется, возвращаем false.
3⃣Для каждого столбца col от 0 до cols - 1, формируем строку newWord из символов на позиции (row, col) для каждой строки. Сохраняем newWord в массиве newWords. В конце, если newWords и words равны, возвращаем true, иначе false.
😎 Решение:
import java.util.*;
public class Solution {
public boolean validWordSquare(List<String> words) {
int cols = 0;
int rows = words.size();
List<String> newWords = new ArrayList<>();
for (String word : words) {
cols = Math.max(cols, word.length());
}
if (cols != words.get(0).length() || rows != cols) {
return false;
}
for (int col = 0; col < cols; ++col) {
StringBuilder newWord = new StringBuilder();
for (int row = 0; row < rows; ++row) {
if (col < words.get(row).length()) {
newWord.append(words.get(row).charAt(col));
}
}
newWords.add(newWord.toString());
}
return words.equals(newWords);
}
}
Ставь 👍 и забирай 📚 Базу знаний
Задача: 482. License Key Formatting
Сложность: easy
Вам дан лицензионный ключ, представленный в виде строки s, которая состоит только из буквенно-цифровых символов и тире. Строка разделена на n + 1 групп с помощью n тире. Вам также дано целое число k.
Мы хотим переформатировать строку s так, чтобы каждая группа содержала ровно k символов, за исключением первой группы, которая может быть короче k, но все же должна содержать хотя бы один символ. Кроме того, между двумя группами должно быть вставлено тире, и все строчные буквы следует преобразовать в прописные.
Верните переформатированный лицензионный ключ.
Пример:
👨💻 Алгоритм:
1⃣Инициализация
Установите count в 0 для подсчета символов в текущей группе. Установите ans в пустую строку для хранения конечного результата.
2⃣Итерация по входной строке в обратном порядке
Пропускайте символы '-'. Если текущий символ не '-', добавьте его в ans и увеличьте count на 1. Если count достигает k, добавьте '-' в ans и сбросьте count.
3⃣Завершение
Проверьте, есть ли в конце строки ans тире, и удалите его, если оно есть. Переверните строку ans и верните её.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Вам дан лицензионный ключ, представленный в виде строки s, которая состоит только из буквенно-цифровых символов и тире. Строка разделена на n + 1 групп с помощью n тире. Вам также дано целое число k.
Мы хотим переформатировать строку s так, чтобы каждая группа содержала ровно k символов, за исключением первой группы, которая может быть короче k, но все же должна содержать хотя бы один символ. Кроме того, между двумя группами должно быть вставлено тире, и все строчные буквы следует преобразовать в прописные.
Верните переформатированный лицензионный ключ.
Пример:
Input: s = "5F3Z-2e-9-w", k = 4
Output: "5F3Z-2E9W"
Explanation: The string s has been split into two parts, each part has 4 characters.
Note that the two extra dashes are not needed and can be removed.
👨💻 Алгоритм:
1⃣Инициализация
Установите count в 0 для подсчета символов в текущей группе. Установите ans в пустую строку для хранения конечного результата.
2⃣Итерация по входной строке в обратном порядке
Пропускайте символы '-'. Если текущий символ не '-', добавьте его в ans и увеличьте count на 1. Если count достигает k, добавьте '-' в ans и сбросьте count.
3⃣Завершение
Проверьте, есть ли в конце строки ans тире, и удалите его, если оно есть. Переверните строку ans и верните её.
😎 Решение:
class Solution {
public String licenseKeyFormatting(String s, int k) {
int count = 0;
StringBuilder ans = new StringBuilder();
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) != '-') {
ans.append(Character.toUpperCase(s.charAt(i)));
count++;
if (count == k) {
ans.append('-');
count = 0;
}
}
}
if (ans.length() > 0 && ans.charAt(ans.length() - 1) == '-') {
ans.deleteCharAt(ans.length() - 1);
}
return ans.reverse().toString();
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 820. Short Encoding of Words
Сложность: medium
Допустимым кодированием массива слов является любая опорная строка s и массив индексов indices, такие что:
words.length == indices.length
Опорная строка s заканчивается символом '#'.
Для каждого индекса indices[i], подстрока строки s, начинающаяся с indices[i] и заканчивающаяся (но не включительно) следующим символом '#', равна words[i].
Дан массив слов, верните длину самой короткой возможной опорной строки s для любого допустимого кодирования слов.
Пример:
👨💻 Алгоритм:
1⃣Поскольку слово имеет не более 6 собственных суффиксов (так как words[i].length <= 7), давайте итерироваться по всем из них. Для каждого собственного суффикса мы попытаемся удалить его из нашего списка слов. Для эффективности сделаем words множеством.
2⃣Затем создадим список оставшихся слов и сформируем опорную строку, объединяя каждое слово с символом '#'.
3⃣В конце вернем длину полученной опорной строки.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Допустимым кодированием массива слов является любая опорная строка s и массив индексов indices, такие что:
words.length == indices.length
Опорная строка s заканчивается символом '#'.
Для каждого индекса indices[i], подстрока строки s, начинающаяся с indices[i] и заканчивающаяся (но не включительно) следующим символом '#', равна words[i].
Дан массив слов, верните длину самой короткой возможной опорной строки s для любого допустимого кодирования слов.
Пример:
Input: words = ["time", "me", "bell"]
Output: 10
Explanation: A valid encoding would be s = "time#bell#" and indices = [0, 2, 5].
words[0] = "time", the substring of s starting from indices[0] = 0 to the next '#' is underlined in "time#bell#"
words[1] = "me", the substring of s starting from indices[1] = 2 to the next '#' is underlined in "time#bell#"
words[2] = "bell", the substring of s starting from indices[2] = 5 to the next '#' is underlined in "time#bell#"
👨💻 Алгоритм:
1⃣Поскольку слово имеет не более 6 собственных суффиксов (так как words[i].length <= 7), давайте итерироваться по всем из них. Для каждого собственного суффикса мы попытаемся удалить его из нашего списка слов. Для эффективности сделаем words множеством.
2⃣Затем создадим список оставшихся слов и сформируем опорную строку, объединяя каждое слово с символом '#'.
3⃣В конце вернем длину полученной опорной строки.
😎 Решение:
class Solution {
public int minimumLengthEncoding(String[] words) {
Set<String> good = new HashSet<>(Arrays.asList(words));
for (String word : words) {
for (int k = 1; k < word.length(); k++) {
good.remove(word.substring(k));
}
}
int length = 0;
for (String word : good) {
length += word.length() + 1;
}
return length;
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 654. Maximum Binary Tree
Сложность: medium
Вам дан целочисленный массив nums без дубликатов. Из nums можно рекурсивно построить максимальное двоичное дерево, используя следующий алгоритм: создайте корневой узел, значение которого равно максимальному значению в nums. Рекурсивно постройте левое поддерево по префиксу подмассива слева от максимального значения. Рекурсивно постройте правое поддерево по суффиксу подмассива справа от максимального значения. Верните максимальное двоичное дерево, построенное из nums.
Пример:
👨💻 Алгоритм:
1⃣Найдите максимальное значение в текущем подмассиве и создайте узел с этим значением.
2⃣Рекурсивно постройте левое поддерево для подмассива слева от максимального значения.
3⃣Рекурсивно постройте правое поддерево для подмассива справа от максимального значения.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан целочисленный массив nums без дубликатов. Из nums можно рекурсивно построить максимальное двоичное дерево, используя следующий алгоритм: создайте корневой узел, значение которого равно максимальному значению в nums. Рекурсивно постройте левое поддерево по префиксу подмассива слева от максимального значения. Рекурсивно постройте правое поддерево по суффиксу подмассива справа от максимального значения. Верните максимальное двоичное дерево, построенное из nums.
Пример:
Input: nums = [3,2,1,6,0,5]
Output: [6,3,5,null,2,0,null,null,1]
👨💻 Алгоритм:
1⃣Найдите максимальное значение в текущем подмассиве и создайте узел с этим значением.
2⃣Рекурсивно постройте левое поддерево для подмассива слева от максимального значения.
3⃣Рекурсивно постройте правое поддерево для подмассива справа от максимального значения.
😎 Решение:
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return build(nums, 0, nums.length);
}
private TreeNode build(int[] nums, int l, int r) {
if (l == r) return null;
int maxIndex = max(nums, l, r);
TreeNode root = new TreeNode(nums[maxIndex]);
root.left = build(nums, l, maxIndex);
root.right = build(nums, maxIndex + 1, r);
return root;
}
private int max(int[] nums, int l, int r) {
int maxIndex = l;
for (int i = l + 1; i < r; i++) {
if (nums[i] > nums[maxIndex]) {
maxIndex = i;
}
}
return maxIndex;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 1510. Stone Game IV
Сложность: hard
Алиса и Боб поочередно играют в игру, причем Алиса начинает первой.
Изначально в куче n камней. В ходе каждого хода игрок удаляет любое ненулевое количество камней, являющееся квадратом целого числа.
Кроме того, если игрок не может сделать ход, он/она проигрывает игру.
Дано положительное целое число n, верните true, если и только если Алиса выиграет игру, иначе верните false, предполагая, что оба игрока играют оптимально.
Пример:
👨💻 Алгоритм:
1⃣Функция dfs(remain) представляет собой проверку, должен ли текущий игрок выиграть при оставшихся remain камнях.
2⃣Для определения результата dfs(n) необходимо итерировать k от 0, чтобы проверить, существует ли такое k, что dfs(remain - k*k) == False. Чтобы предотвратить избыточные вычисления, используйте карту для хранения результатов функции dfs.
3⃣Не забудьте базовые случаи: dfs(0) == False и dfs(1) == True.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Алиса и Боб поочередно играют в игру, причем Алиса начинает первой.
Изначально в куче n камней. В ходе каждого хода игрок удаляет любое ненулевое количество камней, являющееся квадратом целого числа.
Кроме того, если игрок не может сделать ход, он/она проигрывает игру.
Дано положительное целое число n, верните true, если и только если Алиса выиграет игру, иначе верните false, предполагая, что оба игрока играют оптимально.
Пример:
Input: n = 1
Output: true
Explanation: Alice can remove 1 stone winning the game because Bob doesn't have any moves.
👨💻 Алгоритм:
1⃣Функция dfs(remain) представляет собой проверку, должен ли текущий игрок выиграть при оставшихся remain камнях.
2⃣Для определения результата dfs(n) необходимо итерировать k от 0, чтобы проверить, существует ли такое k, что dfs(remain - k*k) == False. Чтобы предотвратить избыточные вычисления, используйте карту для хранения результатов функции dfs.
3⃣Не забудьте базовые случаи: dfs(0) == False и dfs(1) == True.
😎 Решение:
class Solution {
public boolean winnerSquareGame(int n) {
HashMap<Integer, Boolean> cache = new HashMap<>();
cache.put(0, false);
return dfs(cache, n);
}
public boolean dfs(HashMap<Integer, Boolean> cache, int remain) {
if (cache.containsKey(remain)) {
return cache.get(remain);
}
int sqrt_root = (int) Math.sqrt(remain);
for (int i = 1; i <= sqrt_root; i++) {
if (!dfs(cache, remain - i * i)) {
cache.put(remain, true);
return true;
}
}
cache.put(remain, false);
return false;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 848. Shifting Letters
Сложность: medium
Вам дана строка s из строчных букв английского алфавита и целочисленный массив shifts такой же длины.
Назовем shift() буквы следующей буквой в алфавите (с переходом так, что 'z' становится 'a').
Например, shift('a') = 'b', shift('t') = 'u', и shift('z') = 'a'.
Теперь для каждого shifts[i] = x мы хотим сдвинуть первые i + 1 букв строки s на x раз.
Верните итоговую строку после применения всех таких сдвигов к s.
Пример:
👨💻 Алгоритм:
1⃣Вычислите общее количество сдвигов для всех символов строки, используя массив shifts.
2⃣Пройдите по строке s и примените вычисленные сдвиги к каждому символу, начиная с первого и уменьшая количество сдвигов на текущем шаге.
3⃣Постройте и верните итоговую строку после всех сдвигов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана строка s из строчных букв английского алфавита и целочисленный массив shifts такой же длины.
Назовем shift() буквы следующей буквой в алфавите (с переходом так, что 'z' становится 'a').
Например, shift('a') = 'b', shift('t') = 'u', и shift('z') = 'a'.
Теперь для каждого shifts[i] = x мы хотим сдвинуть первые i + 1 букв строки s на x раз.
Верните итоговую строку после применения всех таких сдвигов к s.
Пример:
Input: s = "abc", shifts = [3,5,9]
Output: "rpl"
Explanation: We start with "abc".
After shifting the first 1 letters of s by 3, we have "dbc".
After shifting the first 2 letters of s by 5, we have "igc".
After shifting the first 3 letters of s by 9, we have "rpl", the answer.
👨💻 Алгоритм:
1⃣Вычислите общее количество сдвигов для всех символов строки, используя массив shifts.
2⃣Пройдите по строке s и примените вычисленные сдвиги к каждому символу, начиная с первого и уменьшая количество сдвигов на текущем шаге.
3⃣Постройте и верните итоговую строку после всех сдвигов.
😎 Решение:
class Solution {
public String shiftingLetters(String S, int[] shifts) {
StringBuilder ans = new StringBuilder();
int X = 0;
for (int shift: shifts)
X = (X + shift) % 26;
for (int i = 0; i < S.length(); ++i) {
int index = S.charAt(i) - 'a';
ans.append((char) ((index + X) % 26 + 97));
X = Math.floorMod(X - shifts[i], 26);
}
return ans.toString();
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 754. Reach a Number
Сложность: medium
Вы стоите в позиции 0 на бесконечной числовой прямой. В позиции target находится пункт назначения. Вы можете сделать некоторое количество ходов numMoves так, чтобы: на каждом ходу вы могли пойти либо налево, либо направо. Во время i-го хода (начиная с i == 1 до i == numMoves) вы делаете i шагов в выбранном направлении. Учитывая целое число target, верните минимальное количество ходов (т.е. минимальное numMoves), необходимое для достижения пункта назначения.
Пример:
👨💻 Алгоритм:
1⃣Инициализируйте переменную для текущей позиции (position) и счетчик шагов (steps).
2⃣Используйте цикл, чтобы добавлять к position текущее количество шагов и увеличивать steps.
3⃣Если position достигает или превышает target и разница между position и target четная, остановите цикл и верните steps.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вы стоите в позиции 0 на бесконечной числовой прямой. В позиции target находится пункт назначения. Вы можете сделать некоторое количество ходов numMoves так, чтобы: на каждом ходу вы могли пойти либо налево, либо направо. Во время i-го хода (начиная с i == 1 до i == numMoves) вы делаете i шагов в выбранном направлении. Учитывая целое число target, верните минимальное количество ходов (т.е. минимальное numMoves), необходимое для достижения пункта назначения.
Пример:
Input: target = 2
Output: 3
👨💻 Алгоритм:
1⃣Инициализируйте переменную для текущей позиции (position) и счетчик шагов (steps).
2⃣Используйте цикл, чтобы добавлять к position текущее количество шагов и увеличивать steps.
3⃣Если position достигает или превышает target и разница между position и target четная, остановите цикл и верните steps.
😎 Решение:
public class Solution {
public int reachTarget(int target) {
target = Math.abs(target);
int position = 0;
int steps = 0;
while (position < target || (position - target) % 2 != 0) {
steps++;
position += steps;
}
return steps;
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 67. Add Binary
Сложность: easy
Даны две двоичные строки a и b. Верните их сумму в виде двоичной строки.
Пример:
👨💻 Алгоритм:
1⃣Начните с переноса carry = 0. Если в числе a наименьший бит равен 1, добавьте 1 к carry. То же самое относится к числу b: если в числе b наименьший бит равен 1, добавьте 1 к carry. В этот момент carry для наименьшего бита может быть равен 0 (00), 1 (01) или 2 (10).
2⃣Теперь добавьте наименьший бит carry к ответу и перенесите старший бит carry на следующий порядковый бит.
3⃣Повторяйте те же шаги снова и снова, пока не будут использованы все биты в a и b. Если остаётся ненулевой carry, добавьте его. Теперь переверните строку ответа, и задача выполнена.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Даны две двоичные строки a и b. Верните их сумму в виде двоичной строки.
Пример:
Input: a = "11", b = "1"
Output: "100"
👨💻 Алгоритм:
1⃣Начните с переноса carry = 0. Если в числе a наименьший бит равен 1, добавьте 1 к carry. То же самое относится к числу b: если в числе b наименьший бит равен 1, добавьте 1 к carry. В этот момент carry для наименьшего бита может быть равен 0 (00), 1 (01) или 2 (10).
2⃣Теперь добавьте наименьший бит carry к ответу и перенесите старший бит carry на следующий порядковый бит.
3⃣Повторяйте те же шаги снова и снова, пока не будут использованы все биты в a и b. Если остаётся ненулевой carry, добавьте его. Теперь переверните строку ответа, и задача выполнена.
😎 Решение:
class Solution {
public String addBinary(String a, String b) {
int n = a.length(), m = b.length();
if (n < m) return addBinary(b, a);
StringBuilder sb = new StringBuilder();
int carry = 0, j = m - 1;
for (int i = n - 1; i > -1; --i) {
if (a.charAt(i) == '1') ++carry;
if (j > -1 && b.charAt(j--) == '1') ++carry;
if (carry % 2 == 1) sb.append('1');
else sb.append('0');
carry /= 2;
}
if (carry == 1) sb.append('1');
sb.reverse();
return sb.toString();
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 1167. Minimum Cost to Connect Sticks
Сложность: medium
У вас есть несколько палочек с положительными целыми длинами. Эти длины даны в виде массива sticks, где sticks[i] — длина i-й палочки.
Вы можете соединить любые две палочки длиной x и y в одну палочку, заплатив стоимость x + y. Вы должны соединить все палочки, пока не останется только одна палочка.
Верните минимальную стоимость соединения всех данных палочек в одну палочку таким образом.
Пример:
👨💻 Алгоритм:
1⃣Всегда выбирайте две самые маленькие палочки для соединения и продолжайте делать это, пока не останется только одна палочка. Рассмотрим 4 палочки следующих длин: sticks=[a1, a2, a3, a4]. Попробуем соединить их слева направо. После первого соединения у нас будет: sticks=[(a1 + a2), a3, a4], стоимость=(a1 + a2). После второго соединения у нас будет: sticks=[(a1 + a2 + a3), a4], стоимость=(a1 + a2)+(a1 + a2 + a3). И, наконец, последняя палочка будет выглядеть так: sticks=[(a1 + a2 + a3 + a4)], стоимость=(a1 + a2)+(a1 + a2 + a3)+(a1 + a2 + a3 + a4).
2⃣Итоговая стоимость может быть переписана следующим образом: стоимость=(3a1 + 3a2 + 2a3 + a4). Как видим, палочки, которые соединяются первыми, включаются в итоговую стоимость больше, чем те, которые выбираются позже. Следовательно, оптимально сначала выбирать меньшие палочки, чтобы получить наименьшую стоимость.
3⃣Для выполнения следующих задач будет оптимальна структура данных min heap (которая обычно реализуется как PriorityQueue в большинстве языков): получить две самые маленькие палочки (stick1 и stick2) из массива; добавить одну палочку (stick1 + stick2) обратно в массив. Эта структура данных дает сложность O(logN) для обеих операций.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
У вас есть несколько палочек с положительными целыми длинами. Эти длины даны в виде массива sticks, где sticks[i] — длина i-й палочки.
Вы можете соединить любые две палочки длиной x и y в одну палочку, заплатив стоимость x + y. Вы должны соединить все палочки, пока не останется только одна палочка.
Верните минимальную стоимость соединения всех данных палочек в одну палочку таким образом.
Пример:
Input: sticks = [5]
Output: 0
Explanation: There is only one stick, so you don't need to do anything. The total cost is 0.
👨💻 Алгоритм:
1⃣Всегда выбирайте две самые маленькие палочки для соединения и продолжайте делать это, пока не останется только одна палочка. Рассмотрим 4 палочки следующих длин: sticks=[a1, a2, a3, a4]. Попробуем соединить их слева направо. После первого соединения у нас будет: sticks=[(a1 + a2), a3, a4], стоимость=(a1 + a2). После второго соединения у нас будет: sticks=[(a1 + a2 + a3), a4], стоимость=(a1 + a2)+(a1 + a2 + a3). И, наконец, последняя палочка будет выглядеть так: sticks=[(a1 + a2 + a3 + a4)], стоимость=(a1 + a2)+(a1 + a2 + a3)+(a1 + a2 + a3 + a4).
2⃣Итоговая стоимость может быть переписана следующим образом: стоимость=(3a1 + 3a2 + 2a3 + a4). Как видим, палочки, которые соединяются первыми, включаются в итоговую стоимость больше, чем те, которые выбираются позже. Следовательно, оптимально сначала выбирать меньшие палочки, чтобы получить наименьшую стоимость.
3⃣Для выполнения следующих задач будет оптимальна структура данных min heap (которая обычно реализуется как PriorityQueue в большинстве языков): получить две самые маленькие палочки (stick1 и stick2) из массива; добавить одну палочку (stick1 + stick2) обратно в массив. Эта структура данных дает сложность O(logN) для обеих операций.
😎 Решение:
import java.util.PriorityQueue;
class Solution {
public int connectSticks(int[] sticks) {
int totalCost = 0;
PriorityQueue<Integer> pq = new PriorityQueue<>();
for (int stick : sticks) {
pq.add(stick);
}
while (pq.size() > 1) {
int stick1 = pq.poll();
int stick2 = pq.poll();
int cost = stick1 + stick2;
totalCost += cost;
pq.add(cost);
}
return totalCost;
}
}
Ставь 👍 и забирай 📚 Базу знаний
Задача: 846. Hand of Straights
Сложность: medium
У Алисы есть некоторое количество карт, и она хочет переставить карты в группы так, чтобы каждая группа была размером groupSize и состояла из groupSize последовательных карт.
Дан целочисленный массив hand, где hand[i] — это значение, написанное на i-й карте, и целое число groupSize. Верните true, если она может переставить карты, или false в противном случае.
Пример:
👨💻 Алгоритм:
1⃣Проверьте, делится ли длина массива hand на groupSize. Если нет, верните false.
2⃣Создайте карту cardCount для хранения количества каждой карты в массиве hand.
3⃣Итерируйте по массиву hand и обновляйте карту cardCount. Затем итерируйте снова для создания групп:
Найдите начальную карту startCard для потенциальной последовательности, уменьшая startCard, пока не найдёте карту, которая отсутствует в карте cardCount.
Попробуйте сформировать последовательность из groupSize карт, начиная с startCard. Если какая-либо карта в потенциальной последовательности отсутствует в карте cardCount, верните false.
Если последовательность можно сформировать, уменьшите количество каждой карты в последовательности в карте cardCount.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: 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;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: №45. Jump Game II
Сложность: medium
Вам дан массив целых чисел
Изначально вы находитесь на
Нужно вернуть минимальное количество прыжков, необходимых для достижения последнего элемента массива
Гарантируется, что добраться до конца можно.
Пример:
👨💻 Алгоритм:
1⃣Начало — текущие настройки— его конец ,Завести три переменные: near— начало стандартной настройки, far— его конец, jumps— количество прыжков.
2⃣Не достиг конца массива , находим максим.) в пределах текущей позиции ( доНе farдойдя до конца массива, находим ступеньку достижимой позиции ( farthest) в пределах текущей позиции ( nearдо far).
3⃣Обновляем границы границы ( nearи far) и увеличиваем счётчик прыжков.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан массив целых чисел
nums длины n, где каждый элемент nums[i] представляет максимальную длину прыжка вперёд с индекса i. Изначально вы находитесь на
nums[0]. Нужно вернуть минимальное количество прыжков, необходимых для достижения последнего элемента массива
nums[n - 1]. Гарантируется, что добраться до конца можно.
Пример:
Input: nums = [2,3,1,1,4] Output: 2
👨💻 Алгоритм:
1⃣Начало — текущие настройки— его конец ,Завести три переменные: near— начало стандартной настройки, far— его конец, jumps— количество прыжков.
2⃣Не достиг конца массива , находим максим.) в пределах текущей позиции ( доНе farдойдя до конца массива, находим ступеньку достижимой позиции ( farthest) в пределах текущей позиции ( nearдо far).
3⃣Обновляем границы границы ( nearи far) и увеличиваем счётчик прыжков.
😎 Решение:
class Solution {
public int jump(int[] nums) {
int near = 0, far = 0, jumps = 0;
while (far < nums.length - 1) {
int farthest = 0;
for (int i = near; i <= far; i++) {
farthest = Math.max(farthest, i + nums[i]);
}
near = far + 1;
far = farthest;
jumps++;
}
return jumps;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 941. Valid Mountain Array
Сложность: easy
Задав массив целых чисел arr, верните true тогда и только тогда, когда он является допустимым горным массивом. Напомним, что arr является горным массивом тогда и только тогда, когда: arr.length >= 3 Существует некоторое i с 0 < i < arr.length - 1 такое, что: arr[0] < arr[1] < ... < arr[i - 1] < arr[i] arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Пример:
👨💻 Алгоритм:
1⃣Убедиться, что длина массива не меньше 3.
2⃣Найти вершину горы, которая удовлетворяет условиям горного массива.
Проверить, что все элементы слева от вершины строго возрастают.
Проверить, что все элементы справа от вершины строго убывают.
3⃣Вернуть true, если оба условия выполнены, иначе вернуть false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Задав массив целых чисел arr, верните true тогда и только тогда, когда он является допустимым горным массивом. Напомним, что arr является горным массивом тогда и только тогда, когда: arr.length >= 3 Существует некоторое i с 0 < i < arr.length - 1 такое, что: arr[0] < arr[1] < ... < arr[i - 1] < arr[i] arr[i] > arr[i + 1] > ... > arr[arr.length - 1]
Пример:
Input: arr = [2,1]
Output: false
👨💻 Алгоритм:
1⃣Убедиться, что длина массива не меньше 3.
2⃣Найти вершину горы, которая удовлетворяет условиям горного массива.
Проверить, что все элементы слева от вершины строго возрастают.
Проверить, что все элементы справа от вершины строго убывают.
3⃣Вернуть true, если оба условия выполнены, иначе вернуть false.
😎 Решение:
class Solution {
public boolean validMountainArray(int[] arr) {
if (arr.length < 3) return false;
int i = 1;
while (i < arr.length && arr[i] > arr[i - 1]) i++;
if (i == 1 || i == arr.length) return false;
while (i < arr.length && arr[i] < arr[i - 1]) i++;
return i == arr.length;
}
}Ставь 👍 и забирай 📚 Базу знаний
Задача: 905. Sort Array By Parity
Сложность: easy
Если задан целочисленный массив nums, переместите все четные числа в начало массива, а затем все нечетные. Верните любой массив, удовлетворяющий этому условию.
Пример:
👨💻 Алгоритм:
1⃣Создать два списка: один для четных чисел, другой для нечетных.
2⃣Пройтись по массиву и добавить четные числа в один список, а нечетные в другой.
3⃣Объединить два списка и вернуть результат.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Если задан целочисленный массив nums, переместите все четные числа в начало массива, а затем все нечетные. Верните любой массив, удовлетворяющий этому условию.
Пример:
Input: nums = [3,1,2,4]
Output: [2,4,3,1]
👨💻 Алгоритм:
1⃣Создать два списка: один для четных чисел, другой для нечетных.
2⃣Пройтись по массиву и добавить четные числа в один список, а нечетные в другой.
3⃣Объединить два списка и вернуть результат.
😎 Решение:
class Solution {
public int[] sortArrayByParity(int[] nums) {
List<Integer> evens = new ArrayList<>();
List<Integer> odds = new ArrayList<>();
for (int num : nums) {
if (num % 2 == 0) {
evens.add(num);
} else {
odds.add(num);
}
}
evens.addAll(odds);
int[] result = new int[nums.length];
for (int i = 0; i < result.length; i++) {
result[i] = evens.get(i);
}
return result;
}
}Ставь 👍 и забирай 📚 Базу знаний