C# | LeetCode
3.34K subscribers
198 photos
1 file
1.3K links
Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.me/+nebTPWgpeGs1OWFi
Вопросы собесов t.me/+sjKGQXl79ytkYzIy
Вакансии t.me/+BQFHXZQ0zrViNGIy
Download Telegram
Задача: 424. Longest Repeating Character Replacement
Сложность: medium

Вам дана строка s и целое число k. Вы можете выбрать любой символ строки и заменить его на любой другой заглавный английский символ. Вы можете выполнить эту операцию не более k раз.

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

Пример:
Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.


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

1⃣Определите диапазон поиска. Минимальная длина подстроки с одинаковыми символами всегда равна 1 (назовем ее min), а максимальная длина подстроки может быть равна длине данной строки (назовем ее max). Ответ будет лежать в диапазоне [min, max] (включительно).

2⃣Инициализируйте две переменные lo и hi для бинарного поиска. lo всегда указывает на длину допустимой строки, а hi - на недопустимую длину. Изначально lo равно 1, а hi равно max+1.

3⃣Выполните бинарный поиск, чтобы найти максимальное значение lo, которое представляет самую длинную допустимую подстроку. В конце lo будет содержать ответ, а hi будет на единицу больше lo.

😎 Решение:
public class Solution {
public int CharacterReplacement(string s, int k) {
int lo = 1;
int hi = s.Length + 1;

while (lo + 1 < hi) {
int mid = lo + (hi - lo) / 2;
if (CanMakeValidSubstring(s, mid, k)) {
lo = mid;
} else {
hi = mid;
}
}
return lo;
}

private bool CanMakeValidSubstring(string s, int substringLength, int k) {
int[] freqMap = new int[26];
int maxFrequency = 0;
int start = 0;
for (int end = 0; end < s.Length; end++) {
freqMap[s[end] - 'A']++;

if (end + 1 - start > substringLength) {
freqMap[s[start] - 'A']--;
start++;
}

maxFrequency = Math.Max(maxFrequency, freqMap[s[end] - 'A']);
if (substringLength - maxFrequency <= k) {
return true;
}
}
return false;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 892. Surface Area of 3D Shapes
Сложность: easy

Вам дана сетка n x n, на которой вы разместили несколько кубиков 1 x 1 x 1. Каждое значение v = grid[i][j] представляет собой башню из v кубиков, размещенных на вершине ячейки (i, j). После размещения кубиков вы решили склеить все непосредственно прилегающие кубики друг с другом, образовав несколько неправильных 3D-фигур. Верните общую площадь поверхности получившихся фигур. Примечание: нижняя грань каждой фигуры учитывается в площади ее поверхности.

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


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

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

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

3⃣Просуммировать все значения площадей для получения итоговой площади поверхности.

😎 Решение:
public int SurfaceArea(int[][] grid) {
int n = grid.Length;
int area = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] > 0) {
area += (grid[i][j] * 4) + 2;
}
if (i > 0) {
area -= Math.Min(grid[i][j], grid[i-1][j]) * 2;
}
if (j > 0) {
area -= Math.Min(grid[i][j], grid[i][j-1]) * 2;
}
}
}
return area;
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 914. X of a Kind in a Deck of Cards
Сложность: easy

Вам дан целочисленный массив deck, где deck[i] - число, написанное на i-й карте. Разделите карты на одну или несколько групп так, чтобы: в каждой группе было ровно x карт, где x > 1, и на всех картах в одной группе было написано одно и то же целое число. Верните true, если такое разделение возможно, или false в противном случае.

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


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

1⃣Создать словарь для подсчета частоты каждого числа в массиве deck.

2⃣Найти наибольший общий делитель (НОД) всех частот.

3⃣Проверить, больше ли НОД 1, чтобы определить, можно ли разделить карты на группы.

😎 Решение:
using System;
using System.Collections.Generic;
using System.Linq;

public class Solution {
public bool HasGroupsSizeX(int[] deck) {
var count = deck.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
var freqValues = count.Values.ToList();
var g = freqValues.Aggregate(Gcd);
return g > 1;
}

private int Gcd(int a, int b) {
while (b != 0) {
int temp = a % b;
a = b;
b = temp;
}
return a;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1519. Number of Nodes in the Sub-Tree With the Same Label
Сложность: medium

Вам дано дерево (т.е. связный неориентированный граф без циклов), состоящее из n узлов, пронумерованных от 0 до n - 1, и ровно n - 1 ребра. Корнем дерева является узел 0, и каждый узел дерева имеет метку, которая является строчной буквой, указанной в строке labels (т.е. узел с номером i имеет метку labels[i]).

Массив edges дан в форме edges[i] = [ai, bi], что означает, что существует ребро между узлами ai и bi в дереве.

Верните массив размера n, где ans[i] — это количество узлов в поддереве узла i, которые имеют ту же метку, что и узел i.

Поддерево дерева T — это дерево, состоящее из узла в T и всех его дочерних узлов.

Пример:
Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd"
Output: [2,1,1,1,1,1,1]
Explanation: Node 0 has label 'a' and its sub-tree has node 2 with label 'a' as well, thus the answer is 2. Notice that any node is part of its sub-tree.
Node 1 has a label 'b'. The sub-tree of node 1 contains nodes 1,4 and 5, as nodes 4 and 5 have different labels than node 1, the answer is just 1 (the node itself).


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

1⃣Создайте список смежности, где adj[X] содержит всех соседей узла X.

2⃣Инициализируйте массив ans, хранящий ответ для каждого узла, и заполните его нулями.

3⃣Начните обход в глубину (DFS).

😎 Решение:
public class Solution {
private int[] Dfs(int node, int parent, Dictionary<int, List<int>> adj, char[] labels, int[] ans) {
int[] nodeCounts = new int[26];
nodeCounts[labels[node] - 'a'] = 1;

if (!adj.ContainsKey(node))
return nodeCounts;

foreach (int child in adj[node]) {
if (child == parent) {
continue;
}
int[] childCounts = Dfs(child, node, adj, labels, ans);
for (int i = 0; i < 26; i++) {
nodeCounts[i] += childCounts[i];
}
}

ans[node] = nodeCounts[labels[node] - 'a'];
return nodeCounts;
}

public int[] CountSubTrees(int n, int[][] edges, string labels) {
var adj = new Dictionary<int, List<int>>();
foreach (var edge in edges) {
if (!adj.ContainsKey(edge[0])) {
adj[edge[0]] = new List<int>();
}
if (!adj.ContainsKey(edge[1])) {
adj[edge[1]] = new List<int>();
}
adj[edge[0]].Add(edge[1]);
adj[edge[1]].Add(edge[0]);
}

var ans = new int[n];
Dfs(0, -1, adj, labels.ToCharArray(), ans);
return ans;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1535. Find the Winner of an Array Game
Сложность: medium

Дан целочисленный массив arr из различных целых чисел и целое число k.

Игра будет проводиться между первыми двумя элементами массива (т.е. arr[0] и arr[1]). В каждом раунде игры мы сравниваем arr[0] с arr[1], большее число побеждает и остается на позиции 0, а меньшее число перемещается в конец массива. Игра заканчивается, когда одно число выигрывает k подряд раундов.

Верните число, которое выиграет игру.

Гарантируется, что у игры будет победитель.

Пример:
Input: arr = [2,1,3,5,4,6,7], k = 2
Output: 5
Explanation: Let's see the rounds of the game:
Round | arr | winner | win_count
1 | [2,1,3,5,4,6,7] | 2 | 1
2 | [2,3,5,4,6,7,1] | 3 | 1
3 | [3,5,4,6,7,1,2] | 5 | 1
4 | [5,4,6,7,1,2,3] | 5 | 2
So we can see that 4 rounds will be played and 5 is the winner because it wins 2 consecutive games.


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

1⃣Инициализируйте maxElement как максимальный элемент в arr, queue как очередь с элементами массива, кроме первого, curr = arr[0] и winstreak = 0.

2⃣Пока очередь не пуста (или используйте бесконечный цикл), извлеките opponent из начала очереди. Если curr > opponent, добавьте opponent в конец очереди и увеличьте winstreak на 1. В противном случае добавьте curr в конец очереди, установите curr = opponent и winstreak = 1.

3⃣Если winstreak = k или curr = maxElement, верните curr. Код никогда не должен достигать этой точки, так как гарантированно есть победитель. Верните любое значение.

😎 Решение:
public class Solution {
public int GetWinner(int[] arr, int k) {
int maxElement = arr[0];
Queue<int> queue = new Queue<int>();
for (int i = 1; i < arr.Length; i++) {
maxElement = Math.Max(maxElement, arr[i]);
queue.Enqueue(arr[i]);
}

int curr = arr[0];
int winstreak = 0;

while (queue.Count > 0) {
int opponent = queue.Dequeue();

if (curr > opponent) {
queue.Enqueue(opponent);
winstreak++;
} else {
queue.Enqueue(curr);
curr = opponent;
winstreak = 1;
}

if (winstreak == k || curr == maxElement) {
return curr;
}
}

return -1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
💊1
Задача: 667. Beautiful Arrangement II
Сложность: medium

Даны два целых числа n и k, составьте список answer, содержащий n различных положительных чисел в диапазоне от 1 до n, который соответствует следующему требованию:

Предположим, что этот список answer = [a1, a2, a3, ... , an], тогда список [|a1 - a2|, |a2 - a3|, |a3 - a4|, ... , |an-1 - an|] имеет ровно k различных чисел. Верните список answer. Если существует несколько допустимых ответов, верните любой из них.

Пример:
Input: n = 3, k = 1
Output: [1,2,3]
Explanation: The [1,2,3] has three different positive integers ranging from 1 to 3, and the [1,1] has exactly 1 distinct integer: 1


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

1⃣Инициализация списка:
Начните с создания списка от 1 до n: [1, 2, 3, ..., n].

2⃣Конструирование шаблона с k различиями:
Для обеспечения k различных значений разностей используйте следующий подход:
Включайте числа попеременно с конца и начала списка, начиная с n и 1, чтобы создать как можно больше уникальных разностей.
Если требуется меньше k, оставшиеся числа просто добавляйте в порядке возрастания, чтобы не увеличивать количество уникальных разностей.

3⃣Заполнение списка:
Заполните оставшуюся часть списка последовательными числами, чтобы сохранить уникальные числа в диапазоне от 1 до n.

😎 Решение:
public class Solution {
public int[] ConstructArray(int n, int k) {
int[] answer = new int[n];
int left = 1, right = n;

for (int i = 0; i <= k; i++) {
if (i % 2 == 0) {
answer[i] = left++;
} else {
answer[i] = right--;
}
}

if (k % 2 == 0) {
for (int i = k + 1; i < n; i++) {
answer[i] = right--;
}
} else {
for (int i = k + 1; i < n; i++) {
answer[i] = left++;
}
}

return answer;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 985. Sum of Even Numbers After Queries
Сложность: medium

Дан целочисленный массив nums и массив queries, где queries[i] = [vali, indexi].

Для каждого запроса i, сначала примените nums[indexi] = nums[indexi] + vali, затем выведите сумму четных значений nums.

Верните целочисленный массив answer, где answer[i] - это ответ на i-й запрос.

Пример:
Input: nums = [1], queries = [[4,0]]
Output: [0]


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

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

2⃣Обработка запросов:
Создать пустой массив result для хранения ответов на каждый запрос.
Для каждого запроса [val, index] из массива queries выполнить следующие действия:
Если значение nums[index] четное, вычесть его из evenSum.
Обновить nums[index] добавлением val.
Если новое значение nums[index] четное, добавить его к evenSum.
Добавить текущее значение evenSum в массив result.

3⃣Возврат результата:
Вернуть массив result, содержащий ответы на все запросы.

😎 Решение:
public class Solution {
public int[] SumEvenAfterQueries(int[] nums, int[][] queries) {
int evenSum = nums.Where(x => x % 2 == 0).Sum();
int[] result = new int[queries.Length];

for (int i = 0; i < queries.Length; i++) {
int val = queries[i][0], index = queries[i][1];
if (nums[index] % 2 == 0) {
evenSum -= nums[index];
}
nums[index] += val;
if (nums[index] % 2 == 0) {
evenSum += nums[index];
}
result[i] = evenSum;
}

return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 789. Escape The Ghosts
Сложность: medium

Вы играете в упрощенную игру PAC-MAN на бесконечной 2D-сетке. Вы начинаете в точке [0, 0], и у вас есть конечная точка target = [xtarget, ytarget], к которой вы пытаетесь добраться. На карте находятся несколько привидений, их начальные позиции заданы в виде двумерного массива ghosts, где ghosts[i] = [xi, yi] представляет начальную позицию i-го привидения. Все входные данные являются целочисленными координатами.

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

Вы сможете сбежать, если и только если сможете достичь цели раньше, чем любое привидение достигнет вас. Если вы достигнете любой клетки (включая конечную точку) одновременно с привидением, это не считается побегом.

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

Пример:
Input: ghosts = [[1,0],[0,3]], target = [0,1]
Output: true
Explanation: You can reach the destination (0, 1) after 1 turn, while the ghosts located at (1, 0) and (0, 3) cannot catch up with you.


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

1⃣Проверьте, что наше таксическое расстояние до цели меньше, чем расстояние от любого привидения до цели.

2⃣Если это так, мы можем гарантированно добраться до цели раньше любого привидения.

3⃣Если привидение может добраться до цели раньше нас или одновременно с нами, побег невозможен.

😎 Решение:
public class Solution {
public bool EscapeGhosts(int[][] ghosts, int[] target) {
int playerDistance = Taxi(new int[] {0, 0}, target);
foreach (var ghost in ghosts) {
if (Taxi(ghost, target) <= playerDistance) {
return false;
}
}
return true;
}

private int Taxi(int[] P, int[] Q) {
return Math.Abs(P[0] - Q[0]) + Math.Abs(P[1] - Q[1]);
}
}


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

Дан корень бинарного дерева, верните максимальную ширину данного дерева.

Максимальная ширина дерева - это максимальная ширина среди всех уровней.

Ширина одного уровня определяется как расстояние между конечными узлами (самыми левыми и самыми правыми ненулевыми узлами), где нулевые узлы между конечными узлами, которые присутствовали бы в полном бинарном дереве, продолжающемся до этого уровня, также учитываются при вычислении длины.

Гарантируется, что ответ будет в диапазоне 32-битного знакового целого числа.

Пример:
Input: root = [1,3,2,5,3,null,9]
Output: 4
Explanation: The maximum width exists in the third level with length 4 (5,3,null,9).


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

1⃣Инициализация:
Создайте очередь для хранения узлов и их позиций на уровне.
Начните с корневого узла и его позиции 0.

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

3⃣Обновление максимальной ширины:
Обновите максимальную ширину, если текущая ширина уровня больше.

😎 Решение:
using System;
using System.Collections.Generic;

public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x) { val = x; }
}

public class Solution {
public int WidthOfBinaryTree(TreeNode root) {
if (root == null) return 0;

int maxWidth = 0;
Queue<(TreeNode node, int pos)> queue = new Queue<(TreeNode, int)>();
queue.Enqueue((root, 0));

while (queue.Count > 0) {
int levelSize = queue.Count;
int firstPos = queue.Peek().pos;
for (int i = 0; i < levelSize; i++) {
var (node, pos) = queue.Dequeue();
if (node.left != null) queue.Enqueue((node.left, 2 * pos));
if (node.right != null) queue.Enqueue((node.right, 2 * pos + 1));
}
maxWidth = Math.Max(maxWidth, queue.Peek().pos - firstPos + 1);
}

return maxWidth;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1246. Palindrome Removal
Сложность: hard

Вам дан целочисленный массив arr. За один ход вы можете выбрать палиндромный подмассив arr[i], arr[i + 1], ..., arr[j], где i <= j, и удалить этот подмассив из данного массива. Обратите внимание, что после удаления подмассива элементы слева и справа от него перемещаются, чтобы заполнить пробел, образовавшийся в результате удаления. Верните минимальное количество ходов, необходимое для удаления всех чисел из массива.

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


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

1⃣Базовый случай:
Если подмассив состоит из одного элемента, то его удаление займет 1 ход, поэтому dp[i][i] = 1.

2⃣Рекурсивный случай:
Если arr[i] == arr[j], то мы можем удалить их в одном ходе, если подмассив arr[i+1...j-1] можно удалить за dp[i+1][j-1] ходов, тогда dp[i][j] = dp[i+1][j-1] (если удалим подмассив arr[i+1...j-1] и затем удалим arr[i] и arr[j]).

3⃣В противном случае, минимальное количество ходов для удаления подмассива arr[i...j] будет равно 1 + минимум ходов для удаления каждого из подмассивов arr[i...k] и arr[k+1...j], где i <= k < j. То есть, dp[i][j] = min(dp[i][k] + dp[k+1][j]) для всех k от i до j-1.

😎 Решение:
using System;

public class Solution {
public int MinMovesToDelete(int[] arr) {
int n = arr.Length;
int[,] dp = new int[n, n];

for (int i = 0; i < n; i++) {
dp[i, i] = 1;
}

for (int length = 2; length <= n; length++) {
for (int i = 0; i <= n - length; i++) {
int j = i + length - 1;
if (arr[i] == arr[j]) {
dp[i, j] = length > 2 ? dp[i + 1, j - 1] : 1;
} else {
dp[i, j] = int.MaxValue;
for (int k = i; k < j; k++) {
dp[i, j] = Math.Min(dp[i, j], dp[i, k] + dp[k + 1, j]);
}
}
}
}
return dp[0, n - 1];
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 251. Flatten 2D Vector
Сложность: medium

Разработайте итератор для разворачивания двумерного вектора. Он должен поддерживать операции next и hasNext.

Реализуйте класс Vector2D:

Vector2D(int[][] vec) инициализирует объект двумерным вектором vec.
next() возвращает следующий элемент из двумерного вектора и перемещает указатель на один шаг вперед. Вы можете предположить, что все вызовы next допустимы.
hasNext() возвращает true, если в векторе еще остались элементы, и false в противном случае.

Пример:
Input
["Vector2D", "next", "next", "next", "hasNext", "hasNext", "next", "hasNext"]
[[[[1, 2], [3], [4]]], [], [], [], [], [], [], []]
Output
[null, 1, 2, 3, true, true, 4, false]

Explanation
Vector2D vector2D = new Vector2D([[1, 2], [3], [4]]);
vector2D.next(); // return 1
vector2D.next(); // return 2
vector2D.next(); // return 3
vector2D.hasNext(); // return True
vector2D.hasNext(); // return True
vector2D.next(); // return 4
vector2D.hasNext(); // return False


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

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

2⃣Проверка доступности: Реализуйте метод hasNext(), который просто проверяет, находится ли индекс position в пределах допустимых индексов массива nums. Этот метод вернет true, если position указывает на действительный индекс, и false в противном случае.

3⃣Получение следующего элемента: Метод next() возвращает элемент в текущей позиции position и продвигает указатель position на следующий индекс. Эта операция обеспечивает, что после вызова next(), position обновляется и указывает на следующий элемент, готовый к следующему вызову next().

😎 Решение:
using System.Collections.Generic;

public class Vector2D {
private List<int> nums;
private int position;

public Vector2D(IList<IList<int>> v) {
nums = new List<int>();
foreach (var innerList in v) {
nums.AddRange(innerList);
}
position = -1;
}

public int Next() {
position++;
return nums[position];
}

public bool HasNext() {
return position + 1 < nums.Count;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 434. Number of Segments in a String
Сложность: easy

Дана строка s, верните количество сегментов в строке.

Сегмент определяется как непрерывная последовательность символов, отличных от пробелов.

Пример:
Input: s = "Hello, my name is John"
Output: 5
Explanation: The five segments are ["Hello,", "my", "name", "is", "John"]


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

1⃣Инициализируйте счетчик сегментов segment_count равным 0.

2⃣Итеративно пройдитесь по строке s. Для каждого индекса i проверьте, начинается ли на этом индексе сегмент: Если символ s[i] не является пробелом, и (либо это первый символ строки, либо предыдущий символ s[i-1] является пробелом), увеличьте segment_count.

3⃣Верните segment_count.

😎 Решение:
public class Solution {
public int CountSegments(string s) {
int segmentCount = 0;

for (int i = 0; i < s.Length; i++) {
if ((i == 0 || s[i - 1] == ' ') && s[i] != ' ') {
segmentCount++;
}
}

return segmentCount;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Пожизненная PRO подписка на easyoffer по цене одного года.

Акция до 20 февраля. Покупаешь сейчас один раз – пользуешься всю жизнь без лимита, включая все будущие функции.

Запланированные новые фичи на ближайшие пол года:
1. Агрегатор вакансий
2. Улучшение резюме, чтобы проходить ATS системы
3. Генерация уникального резюме и сопроводительного письма под вакансию

Покупай на https://easyoffer.ru/
Задача: 1512. Number of Good Pairs
Сложность: easy

Дан массив целых чисел nums, верните количество хороших пар.

Пара (i, j) называется хорошей, если nums[i] == nums[j] и i < j.

Пример:
Input: nums = [1,2,3,1,1,3]
Output: 4
Explanation: There are 4 good pairs (0,3), (0,4), (3,4), (2,5) 0-indexed.


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

1⃣Инициализируйте переменную ans значением 0.

2⃣Итерируйте i от 0 до nums.length:
Итерируйте j от i + 1 до nums.length:
Если nums[i] == nums[j], увеличьте ans на 1.

3⃣Верните ans.

😎 Решение:
public class Solution {
public int NumIdenticalPairs(int[] nums) {
int ans = 0;
for (int i = 0; i < nums.Length; i++) {
for (int j = i + 1; j < nums.Length; j++) {
if (nums[i] == nums[j]) {
ans++;
}
}
}
return ans;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: №24. Swap Nodes in Pairs
Сложность: medium

Учитывая связанный список, поменяйте местами каждые два соседних узла и верните его голову. Вы должны решить проблему, не изменяя значения в узлах списка (т. е. изменять можно только сами узлы).

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


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

1⃣Использовать фиктивный (dummy) узел, чтобы упростить обработку начала списка.

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

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

😎 Решение:
public class Solution {
public ListNode SwapPairs(ListNode head) {
ListNode dummy = new ListNode(0, head);
ListNode prev = dummy;

while (head != null && head.next != null) {
ListNode first = head;
ListNode second = head.next;

prev.next = second;
first.next = second.next;
second.next = first;

prev = first;
head = first.next;
}

return dummy.next;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 728. Self Dividing Numbers
Сложность: hard

Например, 128 является саморазделяющимся числом, потому что 128 % 1 == 0, 128 % 2 == 0 и 128 % 8 == 0. Саморазделяющееся число не может содержать цифру ноль. Если даны два целых числа left и right, верните список всех саморазделяющихся чисел в диапазоне [left, right].

Пример:
Input: left = 1, right = 22
Output: [1,2,3,4,5,6,7,8,9,11,12,15,22]


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

1⃣Переберите все числа в диапазоне от left до right.

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

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

😎 Решение:
public class Solution {
public IList<int> SelfDividingNumbers(int left, int right) {
List<int> result = new List<int>();
for (int num = left; num <= right; num++) {
if (IsSelfDividing(num)) {
result.Add(num);
}
}
return result;
}

private bool IsSelfDividing(int num) {
int n = num;
while (n > 0) {
int digit = n % 10;
if (digit == 0 || num % digit != 0) {
return false;
}
n /= 10;
}
return true;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1203. Sort Items by Groups Respecting Dependencies
Сложность: hard

Есть n предметов, каждый из которых принадлежит нулевой или одной из m групп, где group[i] — это группа, к которой принадлежит i-й предмет, и равно -1, если i-й предмет не принадлежит никакой группе. Предметы и группы имеют индексацию с нуля. Группа может не иметь ни одного предмета.

Верните отсортированный список предметов таким образом:
Предметы, принадлежащие одной группе, расположены рядом друг с другом в отсортированном списке.
Существуют некоторые отношения между этими предметами, где beforeItems[i] — это список, содержащий все предметы, которые должны быть перед i-м предметом в отсортированном массиве (слева от i-го предмета).
Верните любое решение, если существует более одного решения, и верните пустой список, если решения не существует.

Пример:
Input: n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3,6],[],[],[]]
Output: [6,3,4,1,5,2,0,7]


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

1⃣Инициализация и создание графов:
Присвоить уникальные идентификаторы группам для элементов без группы.
Создать два графа: item_graph для элементов и group_graph для групп. Также создать два массива для учета входящих рёбер для элементов и групп.

2⃣Построение графов:
Пройти по массиву beforeItems и добавить зависимости между элементами в item_graph, увеличивая счётчик входящих рёбер.
Если элементы принадлежат разным группам, добавить зависимость между группами в group_graph, увеличивая счётчик входящих рёбер.

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

😎 Решение:
public class Solution {
public int[] SortItems(int n, int m, int[] group, IList<IList<int>> beforeItems) {
int groupId = m;
for (int i = 0; i < n; i++) if (group[i] == -1) group[i] = groupId++;

var itemGraph = new Dictionary<int, List<int>>();
var groupGraph = new Dictionary<int, List<int>>();
int[] itemIndegree = new int[n], groupIndegree = new int[groupId];
for (int i = 0; i < n; i++) itemGraph[i] = new List<int>();
for (int i = 0; i < groupId; i++) groupGraph[i] = new List<int>();

for (int curr = 0; curr < n; curr++) {
foreach (var prev in beforeItems[curr]) {
itemGraph[prev].Add(curr);
itemIndegree[curr]++;
if (group[curr] != group[prev]) {
groupGraph[group[prev]].Add(group[curr]);
groupIndegree[group[curr]]++;
}
}
}

var itemOrder = TopologicalSort(itemGraph, itemIndegree);
var groupOrder = TopologicalSort(groupGraph, groupIndegree);
if (itemOrder.Count == 0 || groupOrder.Count == 0) return new int[0];

var orderedGroups = new Dictionary<int, List<int>>();
foreach (var item in itemOrder) {
if (!orderedGroups.ContainsKey(group[item])) orderedGroups[group[item]] = new List<int>();
orderedGroups[group[item]].Add(item);
}

var answerList = new List<int>();
foreach (var groupIndex in groupOrder) {
if (orderedGroups.ContainsKey(groupIndex)) answerList.AddRange(orderedGroups[groupIndex]);
}

return answerList.ToArray();
}

private List<int> TopologicalSort(Dictionary<int, List<int>> graph, int[] indegree) {
var visited = new List<int>();
var stack = new Stack<int>();
foreach (var key in graph.Keys) if (indegree[key] == 0) stack.Push(key);

while (stack.Count > 0) {
var curr = stack.Pop();
visited.Add(curr);
foreach (var next in graph[curr]) if (--indegree[next] == 0) stack.Push(next);
}

return visited.Count == graph.Keys.Count ? visited : new List<int>();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 462. Minimum Moves to Equal Array Elements II
Сложность: medium

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

В одном ходе вы можете увеличить или уменьшить элемент массива на 1.

Тестовые случаи составлены так, что ответ поместится в 32-битное целое число.

Пример:
Input: nums = [1,2,3]
Output: 2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]


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

1⃣Найти минимальный и максимальный элементы в массиве. Пусть k будет числом, к которому должны быть приведены все элементы массива.

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

3⃣Определить минимальное количество ходов среди всех возможных k, что и будет конечным результатом.

😎 Решение:
public class Solution {
public int MinMoves2(int[] nums) {
long ans = long.MaxValue;
int minval = int.MaxValue;
int maxval = int.MinValue;
foreach (int num in nums) {
minval = Math.Min(minval, num);
maxval = Math.Max(maxval, num);
}
for (int i = minval; i <= maxval; i++) {
long sum = 0;
foreach (int num in nums) {
sum += Math.Abs(num - i);
}
ans = Math.Min(ans, sum);
}
return (int) ans;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1071. Greatest Common Divisor of Strings
Сложность: easy

Для двух строк s и t мы говорим, что "t делит s", если и только если s = t + t + t + ... + t (т.е. t соединена сама с собой один или более раз).

Даны две строки str1 и str2, верните наибольшую строку x, такую что x делит и str1, и str2.

Пример:
Input: str1 = "ABCABC", str2 = "ABC"
Output: "ABC"


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

1⃣Найдите более короткую строку среди str1 и str2, для простоты пусть это будет str1.

2⃣Начните с base = str1 и проверьте, состоят ли обе строки str1 и str2 из множителей строки base. Если это так, верните base. В противном случае, попробуйте более короткую строку, удалив последний символ из base.

3⃣Если вы проверили все префиксные строки и не нашли строку GCD, верните "".

😎 Решение:
public class Solution {
public bool Valid(string str1, string str2, int k) {
int len1 = str1.Length, len2 = str2.Length;
if (len1 % k > 0 || len2 % k > 0) {
return false;
} else {
string baseStr = str1.Substring(0, k);
int n1 = len1 / k, n2 = len2 / k;
return str1 == JoinWords(baseStr, n1) && str2 == JoinWords(baseStr, n2);
}
}

public string JoinWords(string str, int k) {
var sb = new StringBuilder();
for (int i = 0; i < k; i++) {
sb.Append(str);
}
return sb.ToString();
}

public string GcdOfStrings(string str1, string str2) {
int len1 = str1.Length, len2 = str2.Length;
for (int i = Math.Min(len1, len2); i >= 1; i--) {
if (Valid(str1, str2, i)) {
return str1.Substring(0, i);
}
}
return "";
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 1150. Check If a Number Is Majority Element in a Sorted Array
Сложность: easy

Дан целочисленный массив nums, отсортированный в неубывающем порядке, и целое число target. Верните true, если target является элементом большинства, или false в противном случае.

Элемент большинства в массиве nums — это элемент, который встречается в массиве более чем nums.length / 2 раз.

Пример:
Input: nums = [2,4,5,5,5,5,5,6,6], target = 5
Output: true
Explanation: The value 5 appears 5 times and the length of the array is 9.
Thus, 5 is a majority element because 5 > 9/2 is true.


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

1⃣Инициализация переменной count:
Инициализируйте переменную count значением 0..

2⃣Итерация по списку nums:
Пройдите по каждому элементу списка nums.
Если элемент num равен target, увеличьте значение переменной count.

3⃣Проверка условия мажоритарного элемента:
Если count больше чем половина длины списка nums, верните true.
В противном случае верните false.

😎 Решение:
public class Solution {
public bool IsMajorityElement(int[] nums, int target) {
int count = 0;
foreach (int num in nums) {
if (num == target) {
count++;
}
}
return count > nums.Length / 2;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Задача: 908. Smallest Range I
Сложность: easy

Вам дан целочисленный массив nums и целое число k. За одну операцию вы можете выбрать любой индекс i, где 0 <= i < nums.length, и изменить nums[i] на nums[i] + x, где x - целое число из диапазона [-k, k]. Эту операцию можно применять не более одного раза для каждого индекса i. Оценка nums - это разница между максимальным и минимальным элементами в nums. Верните минимальную оценку nums после применения указанной операции не более одного раза для каждого индекса в нем.

Пример:
Input: nums = [1], k = 0
Output: 0


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

1⃣Найти минимальное и максимальное значения массива nums.

2⃣Рассчитать потенциальные новые минимальные и максимальные значения после применения операции.

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

😎 Решение:
public class Solution {
public int SmallestRangeI(int[] nums, int k) {
int minVal = int.MaxValue;
int maxVal = int.MinValue;
foreach (int num in nums) {
if (num < minVal) minVal = num;
if (num > maxVal) maxVal = num;
}
return Math.Max(0, (maxVal - k) - (minVal + k));
}
}


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