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

Тесты t.iss.one/+nebTPWgpeGs1OWFi
Вопросы собесов t.iss.one/+sjKGQXl79ytkYzIy
Вакансии t.iss.one/+BQFHXZQ0zrViNGIy
Download Telegram
Задача: 43. Multiply Strings
Сложность: hard

Даны два неотрицательных числа num1 и num2, представленные в виде строк. Нужно вернуть их произведение в виде строки.

Ограничения:
- Нельзя использовать встроенные библиотеки BigInteger.
- Нельзя напрямую конвертировать входные данные в числа.

Пример:
Input: num1 = "2", num2 = "3"  
Output: "6"


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

1⃣Создайте массив длиной n + m, пройдите по цифрам в обратном порядке и перемножьте пару.

2⃣Сумму контроллера в неправильной позиции, обработку переноса при старшем разряде.

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

😎 Решение:
public class Solution {
public string Multiply(string num1, string num2) {
if (num1 == "0" || num2 == "0") return "0";

int n = num1.Length, m = num2.Length;
int[] ans = new int[n + m];

for (int i = n - 1; i >= 0; i--) {
for (int j = m - 1; j >= 0; j--) {
int mul = (num1[i] - '0') * (num2[j] - '0');
int sum = mul + ans[i + j + 1];

ans[i + j + 1] = sum % 10;
ans[i + j] += sum / 10;
}
}

StringBuilder result = new StringBuilder();
foreach (int num in ans) {
if (!(result.Length == 0 && num == 0)) {
result.Append(num);
}
}

return result.ToString();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 970. Powerful Integers
Сложность: medium

Даны три целых числа x, y и bound. Верните список всех мощных чисел, которые имеют значение меньше или равное bound.

Целое число является мощным, если оно может быть представлено как x^i + y^j для некоторых целых чисел i >= 0 и j >= 0.

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

Пример:
Input: x = 2, y = 3, bound = 10
Output: [2,3,4,5,7,9,10]
Explanation:
2 = 20 + 30
3 = 21 + 30
4 = 20 + 31
5 = 21 + 31
7 = 22 + 31
9 = 23 + 30
10 = 20 + 32


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

1⃣Вычислите степени a и b как логарифмы bound по основаниям x и y соответственно. Создайте множество powerfulIntegers для хранения результатов.

2⃣Используйте вложенные циклы, где внешний цикл проходит от 0 до a, а внутренний цикл от 0 до b. На каждом шаге вычисляйте x^i + y^j и, если значение меньше или равно bound, добавляйте его в множество powerfulIntegers.

3⃣Используйте вложенные циклы, где внешний цикл проходит от 0 до a, а внутренний цикл от 0 до b. На каждом шаге вычисляйте x^i + y^j и, если значение меньше или равно bound, добавляйте его в множество powerfulIntegers.

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

public class Solution {
public IList<int> PowerfulIntegers(int x, int y, int bound) {
int a = x == 1 ? bound : (int)(Math.Log(bound) / Math.Log(x));
int b = y == 1 ? bound : (int)(Math.Log(bound) / Math.Log(y));
HashSet<int> powerfulIntegers = new HashSet<int>();

for (int i = 0; i <= a; i++) {
for (int j = 0; j <= b; j++) {
int value = (int)Math.Pow(x, i) + (int)Math.Pow(y, j);
if (value <= bound) {
powerfulIntegers.Add(value);
}
if (y == 1) {
break;
}
}
if (x == 1) {
break;
}
}

return new List<int>(powerfulIntegers);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1168. Optimize Water Distribution in a Village
Сложность: hard

В деревне есть n домов. Мы хотим обеспечить все дома водой, строя колодцы и прокладывая трубы.

Для каждого дома i мы можем либо построить колодец внутри него непосредственно с затратами wells[i - 1] (обратите внимание на -1 из-за нумерации с нуля), либо провести воду из другого колодца с помощью трубы. Затраты на прокладку труб между домами даны в массиве pipes, где каждый pipes[j] = [house1j, house2j, costj] представляет собой стоимость соединения дома house1j и дома house2j с помощью трубы. Соединения двунаправленные, и между одними и теми же домами могут быть несколько допустимых соединений с разными затратами.

Верните минимальные оhttps://leetcode.com/problems/optimize-water-distribution-in-a-village/Figures/1168/PrimAlgDemo.gifбщие затраты на обеспечение всех домов водой.

Пример:
Input: n = 3, wells = [1,2,2], pipes = [[1,2,1],[2,3,1]]
Output: 3
Explanation: The image shows the costs of connecting houses using pipes.
The best strategy is to build a well in the first house with cost 1 and connect the other houses to it with cost 2 so the total cost is 3.


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

1⃣Представление графа: Постройте список смежности для представления графа, где вершины и ребра соответствуют домам и трубам. Список смежности можно представить в виде списка списков или словаря списков.

2⃣Набор для вершин: Используйте набор для поддержания всех вершин, добавленных в окончательное минимальное остовное дерево (MST) во время его построения. С помощью набора можно определить, была ли вершина уже добавлена или нет.

3⃣Очередь с приоритетом (куча): Используйте кучу для реализации жадной стратегии. На каждом шаге определяйте лучшее ребро для добавления на основе стоимости его добавления в дерево. Куча позволяет извлекать минимальный элемент за константное время и удалять минимальный элемент за логарифмическое время. Это идеально подходит для нашей задачи повторного нахождения ребра с наименьшей стоимостью.

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

public class Solution {
public int MinCostToSupplyWater(int n, int[] wells, int[][] pipes) {
var edgesHeap = new PriorityQueue<int[], int[]>(Comparer<int[]>.Create((a, b) => a[0] - b[0]));
var graph = new List<List<int[]>>(n + 1);
for (int i = 0; i < n + 1; ++i) {
graph.Add(new List<int[]>());
}

for (int i = 0; i < wells.Length; ++i) {
graph[0].Add(new int[] { wells[i], i + 1 });
edgesHeap.Enqueue(new int[] { wells[i], i + 1 }, new int[] { wells[i], i + 1 });
}

foreach (var pipe in pipes) {
int house1 = pipe[0], house2 = pipe[1], cost = pipe[2];
graph[house1].Add(new int[] { cost, house2 });
graph[house2].Add(new int[] { cost, house1 });
}

var mstSet = new HashSet<int> { 0 };
int totalCost = 0;

while (mstSet.Count < n + 1) {
var edge = edgesHeap.Dequeue();
int cost = edge[0], nextHouse = edge[1];
if (mstSet.Contains(nextHouse)) continue;
mstSet.Add(nextHouse);
totalCost += cost;
foreach (var neighborEdge in graph[nextHouse]) {
if (!mstSet.Contains(neighborEdge[1])) {
edgesHeap.Enqueue(neighborEdge, neighborEdge);
}
}
}

return totalCost;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 532. K-diff Pairs in an Array
Сложность: medium

Дан массив целых чисел nums и целое число k. Верните количество уникальных пар с разницей k в массиве.

Пара с разницей k — это пара целых чисел (nums[i], nums[j]), для которой выполняются следующие условия:
0 <= i, j < nums.length
i != j
|nums[i] - nums[j]| == k
Обратите внимание, что |val| обозначает абсолютное значение val.

Пример:
Input: nums = [3,1,4,1,5], k = 2
Output: 2
Explanation: There are two 2-diff pairs in the array, (1, 3) and (3, 5).
Although we have two 1s in the input, we should only return the number of unique pairs.


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

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

2⃣ Для каждого ключа в хэш-словаре проверьте, можно ли найти пару, удовлетворяющую условиям:
Если k > 0, проверьте, существует ли ключ, равный x + k.
Если k == 0, проверьте, есть ли более одного вхождения x.

3⃣ Увеличьте счётчик результатов, если условие выполняется.

😎 Решение:
public class Solution {
public int FindPairs(int[] nums, int k) {
var counter = new Dictionary<int, int>();
foreach (int num in nums) {
if (!counter.ContainsKey(num)) {
counter[num] = 0;
}
counter[num]++;
}

int result = 0;
foreach (var entry in counter) {
int x = entry.Key;
int val = entry.Value;
if (k > 0 && counter.ContainsKey(x + k)) {
result++;
} else if (k == 0 && val > 1) {
result++;
}
}

return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 634. Find the Derangement of An Array
Сложность: medium

В комбинаторной математике отклонение - это перестановка элементов множества таким образом, что ни один элемент не оказывается на прежнем месте. Вам дано целое число n. Изначально имеется массив, состоящий из n целых чисел от 1 до n в порядке возрастания, верните количество отклонений, которые он может породить. Поскольку ответ может быть огромным, верните его по модулю 109 + 7.

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


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

1⃣Инициализация массива для хранения результатов
Создайте массив dp для хранения количества отклонений для каждого значения от 0 до n. Установите начальные значения: dp[0] = 1 и dp[1] = 0.

2⃣Вычисление количества отклонений
Используйте динамическое программирование для вычисления количества отклонений для каждого значения от 2 до n. Формула для вычисления: dp[i] = (i - 1) * (dp[i - 1] + dp[i - 2]) % MOD.

3⃣Возвращение результата
Верните значение dp[n], которое будет количеством отклонений для n элементов, по модулю 10^9 + 7.

😎 Решение:
public class Solution {
public int CountDerangements(int n) {
const int MOD = 1000000007;
if (n == 0) return 1;
if (n == 1) return 0;
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 0;
for (int i = 2; i <= n; i++) {
dp[i] = (int)((long)(i - 1) * (dp[i - 1] + dp[i - 2]) % MOD);
}
return dp[n];
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1423. Maximum Points You Can Obtain from Cards
Сложность: medium

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

Дан целочисленный массив cardPoints и целое число k, верните максимальное количество очков, которое вы можете получить.

Пример:
Input: cardPoints = [1,2,3,4,5,6,1], k = 3
Output: 12
Explanation: After the first step, your score will always be 1. However, choosing the rightmost card first will maximize your total score. The optimal strategy is to take the three cards on the right, giving a final score of 1 + 6 + 5 = 12.


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

1⃣Инициализируйте два массива размера k + 1, frontSetOfCards и rearSetOfCards, чтобы хранить суммы очков, полученных при выборе первых i карт и последних i карт в массиве.

2⃣Рассчитайте префиксные суммы для первых k карт и последних k карт.

3⃣Итерируйте от 0 до k и вычисляйте возможное количество очков, выбирая i карт с начала массива и k - i карт с конца, обновляя максимальный результат при необходимости.

😎 Решение:
public class Solution {
public int MaxScore(int[] cardPoints, int k) {
int n = cardPoints.Length;
int[] frontSetOfCards = new int[k + 1];
int[] rearSetOfCards = new int[k + 1];

for (int i = 0; i < k; ++i) {
frontSetOfCards[i + 1] = cardPoints[i] + frontSetOfCards[i];
rearSetOfCards[i + 1] = cardPoints[n - i - 1] + rearSetOfCards[i];
}

int maxScore = 0;
for (int i = 0; i <= k; ++i) {
int currentScore = frontSetOfCards[i] + rearSetOfCards[k - i];
maxScore = Math.Max(maxScore, currentScore);
}

return maxScore;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 296. Best Meeting Point
Сложность: hard

Дан бинарный сетка размером m x n, где каждая 1 обозначает дом одного друга. Верните минимальное общее расстояние путешествия.

Общее расстояние путешествия — это сумма расстояний между домами друзей и точкой встречи.

Расстояние рассчитывается по Манхэттенскому расстоянию, где distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|.

Пример:
Input: grid = [[1,0,0,0,1],[0,0,0,0,0],[0,0,1,0,0]]
Output: 6
Explanation: Given three friends living at (0,0), (0,4), and (2,2).
The point (0,2) is an ideal meeting point, as the total travel distance of 2 + 2 + 2 = 6 is minimal.
So return 6.


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

1⃣Определение координат домов:
Пройдите по сетке и соберите координаты всех домов (ячейки с значением 1) в два списка: один для координат x и один для координат y.

2⃣Нахождение медианы:
Отсортируйте списки координат x и y.
Найдите медианы в обоих списках. Медианы координат x и y укажут оптимальную точку встречи.

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

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

public class Solution {
public int MinTotalDistance(int[][] grid) {
int minDistance = int.MaxValue;
for (int row = 0; row < grid.Length; row++) {
for (int col = 0; col < grid[0].Length; col++) {
int distance = Search(grid, row, col);
minDistance = Math.Min(distance, minDistance);
}
}
return minDistance;
}

private int Search(int[][] grid, int row, int col) {
Queue<Tuple<int, int, int>> q = new Queue<Tuple<int, int, int>>();
q.Enqueue(Tuple.Create(row, col, 0));
int m = grid.Length;
int n = grid[0].Length;
bool[][] visited = new bool[m][];
for (int i = 0; i < m; i++) {
visited[i] = new bool[n];
}
int totalDistance = 0;

while (q.Count > 0) {
var point = q.Dequeue();
int r = point.Item1;
int c = point.Item2;
int d = point.Item3;

if (r < 0 || c < 0 || r >= m || c >= n || visited[r][c]) {
continue;
}

if (grid[r][c] == 1) {
totalDistance += d;
}

visited[r][c] = true;

q.Enqueue(Tuple.Create(r + 1, c, d + 1));
q.Enqueue(Tuple.Create(r - 1, c, d + 1));
q.Enqueue(Tuple.Create(r, c + 1, d + 1));
q.Enqueue(Tuple.Create(r, c - 1, d + 1));
}

return totalDistance;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1283. Find the Smallest Divisor Given a Threshold
Сложность: medium

Дан массив целых чисел nums и целое число threshold. Мы выберем положительный целый делитель, разделим все элементы массива на него и суммируем результат деления. Найдите наименьший делитель, такой что результат, упомянутый выше, меньше или равен threshold.

Каждый результат деления округляется до ближайшего большего целого числа. (Например: 7/3 = 3 и 10/2 = 5).

Гарантируется, что решение существует.

Пример:
Input: nums = [1,2,5,9], threshold = 6
Output: 5
Explanation: We can get a sum to 17 (1+2+5+9) if the divisor is 1.
If the divisor is 4 we can get a sum of 7 (1+1+2+3) and if the divisor is 5 the sum will be 5 (1+1+1+2).


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

1⃣Найдите максимальный элемент массива nums и сохраните его в переменной maxElement.

2⃣Итерация по всем делителям от 1 до maxElement:
Инициализируйте две переменные: sumOfDivisionResults для хранения суммы результатов деления и thresholdExceeded для указания, превышен ли порог.
Итерация по всем элементам массива nums: добавьте результат деления, округленного до ближайшего большего целого числа, в переменную sumOfDivisionResults. Если сумма превышает threshold, установите thresholdExceeded в true и прекратите итерацию по массиву nums.

3⃣Проверьте, был ли превышен порог:
Если порог не был превышен, текущий делитель является наименьшим делителем, поэтому верните его.
Если не найдено возможного делителя, верните -1.

😎 Решение:
public class Solution {
public int SmallestDivisor(int[] nums, int threshold) {
int maxElement = nums.Max();

for (int divisor = 1; divisor <= maxElement; divisor++) {
int sumOfDivisionResults = 0;
bool thresholdExceeded = true;

foreach (int num in nums) {
sumOfDivisionResults += (num + divisor - 1) / divisor;
if (sumOfDivisionResults > threshold) {
thresholdExceeded = false;
break;
}
}

if (thresholdExceeded) {
return divisor;
}
}

return -1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 609. Find Duplicate File in System
Сложность: medium

Получив список paths информации о каталоге, включающий путь к каталогу и все файлы с содержимым в этом каталоге, верните все дубликаты файлов в файловой системе по их путям. Вы можете вернуть ответ в любом порядке. Группа дубликатов состоит как минимум из двух файлов с одинаковым содержимым. Одна строка информации о каталоге во входном списке имеет следующий формат: "root/d1/d2/.../dm f1.txt(f1_content) f2.txt(f2_content) ... fn.txt(fn_content)" Это означает, что в каталоге "root/d1/d2/.../dm" имеется n файлов (f1.txt, f2.txt ... fn.txt) с содержимым (f1_content, f2_content ... fn_content) соответственно. Обратите внимание, что n >= 1 и m >= 0. Если m = 0, это означает, что каталог является только корневым. На выходе получается список групп дублирующихся путей к файлам. Для каждой группы он содержит все пути к файлам, которые имеют одинаковое содержимое. Путь к файлу - это строка, имеющая следующий формат: "каталог_путь/имя_файла.txt".

Пример:
Input: paths = ["root/a 1.txt(abcd) 2.txt(efgh)","root/c 3.txt(abcd)","root/c/d 4.txt(efgh)","root 4.txt(efgh)"]
Output: [["root/a/2.txt","root/c/d/4.txt","root/4.txt"],["root/a/1.txt","root/c/3.txt"]]


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

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

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

3⃣Пройдите по словарю и соберите группы дубликатов, содержащие как минимум два пути.

😎 Решение:
public class Solution {
public IList<IList<string>> FindDuplicate(string[] paths) {
var contentToFilePaths = new Dictionary<string, List<string>>();

foreach (var path in paths) {
var parts = path.Split(' ');
var root = parts[0];

for (int i = 1; i < parts.Length; i++) {
var fileParts = parts[i].Split('(');
var fileName = fileParts[0];
var content = fileParts[1].TrimEnd(')');

var filePath = $"{root}/{fileName}";
if (!contentToFilePaths.ContainsKey(content)) {
contentToFilePaths[content] = new List<string>();
}
contentToFilePaths[content].Add(filePath);
}
}

var result = new List<IList<string>>();
foreach (var kvp in contentToFilePaths) {
if (kvp.Value.Count > 1) {
result.Add(kvp.Value);
}
}

return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 986. Interval List Intersections
Сложность: medium

Вам даны два списка закрытых интервалов, firstList и secondList, где firstList[i] = [starti, endi] и secondList[j] = [startj, endj]. Каждый список интервалов является попарно непересекающимся и отсортированным.

Верните пересечение этих двух списков интервалов.

Закрытый интервал [a, b] (где a <= b) обозначает множество действительных чисел x с a <= x <= b.

Пересечение двух закрытых интервалов - это множество действительных чисел, которые либо пусты, либо представлены как закрытый интервал. Например, пересечение [1, 3] и [2, 4] равно [2, 3].

Пример:
Input: firstList = [[0,2],[5,10],[13,23],[24,25]], secondList = [[1,5],[8,12],[15,24],[25,26]]
Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]


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

1⃣Инициализация указателей:
Завести два указателя i и j, указывающие на начало firstList и secondList соответственно.

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

3⃣Возврат результата:
Вернуть список пересечений.

😎 Решение:
public class Solution {
public int[][] IntervalIntersection(int[][] firstList, int[][] secondList) {
List<int[]> result = new List<int[]>();
int i = 0, j = 0;

while (i < firstList.Length && j < secondList.Length) {
int start = Math.Max(firstList[i][0], secondList[j][0]);
int end = Math.Min(firstList[i][1], secondList[j][1]);

if (start <= end) {
result.Add(new int[]{start, end});
}

if (firstList[i][1] < secondList[j][1]) {
i++;
} else {
j++;
}
}

return result.ToArray();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 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.

😎 Решение:
public class Solution {
public bool IsNStraightHand(int[] hand, int groupSize) {
if (hand.Length % groupSize != 0) {
return false;
}

var cardCount = new Dictionary<int, int>();
foreach (int card in hand) {
if (!cardCount.ContainsKey(card)) {
cardCount[card] = 0;
}
cardCount[card]++;
}

Array.Sort(hand);

foreach (int card in hand) {
if (cardCount[card] == 0) {
continue;
}

for (int nextCard = card; nextCard < card + groupSize; nextCard++) {
if (!cardCount.ContainsKey(nextCard) || cardCount[nextCard] == 0) {
return false;
}
cardCount[nextCard]--;
}
}

return true;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 433. Minimum Genetic Mutation
Сложность: medium

Генетическая строка может быть представлена строкой длиной 8 символов, содержащей символы 'A', 'C', 'G' и 'T'.

Предположим, нам нужно исследовать мутацию от генетической строки startGene до генетической строки endGene, где одна мутация определяется как изменение одного символа в генетической строке.

Например, "AACCGGTT" --> "AACCGGTA" является одной мутацией.
Также существует генетический банк bank, который содержит все допустимые генетические мутации. Генетическая строка должна быть в банке, чтобы считаться допустимой.

Даны две генетические строки startGene и endGene и генетический банк bank, верните минимальное количество мутаций, необходимых для мутации от startGene до endGene. Если такой мутации не существует, верните -1.

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

Пример:
Input: startGene = "AACCGGTT", endGene = "AACCGGTA", bank = ["AACCGGTA"]
Output: 1


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

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

2⃣Выполняйте BFS. На каждом узле, если node == endGene, верните количество шагов, пройденных до этого момента. В противном случае, итеративно заменяйте каждый символ в строке на один из "A", "C", "G", "T" для нахождения соседей. Для каждого соседа, если он еще не был посещен и находится в bank, добавьте его в очередь и в множество seen.

3⃣Если BFS завершился и endGene не был найден, задача невыполнима. Верните -1.

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

public class Solution {
public int MinMutation(string start, string end, string[] bank) {
Queue<string> queue = new Queue<string>();
HashSet<string> seen = new HashSet<string>();
queue.Enqueue(start);
seen.Add(start);

int steps = 0;
while (queue.Count > 0) {
int nodesInQueue = queue.Count;

for (int j = 0; j < nodesInQueue; j++) {
string node = queue.Dequeue();

if (node == end) {
return steps;
}

foreach (char c in "ACGT") {
for (int i = 0; i < node.Length; i++) {
char[] neighborArray = node.ToCharArray();
neighborArray[i] = c;
string neighbor = new string(neighborArray);
if (!seen.Contains(neighbor) && Array.Exists(bank, b => b == neighbor)) {
queue.Enqueue(neighbor);
seen.Add(neighbor);
}
}
}
}

steps++;
}

return -1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 554. Brick Wall
Сложность: medium

Перед вами находится прямоугольная кирпичная стена с n рядами кирпичей. В i-м ряду находится несколько кирпичей одинаковой высоты (то есть один юнит), но они могут быть разной ширины. Общая ширина каждого ряда одинакова.

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

Дан двумерный массив wall, содержащий информацию о стене, верните минимальное количество пересеченных кирпичей после проведения такой вертикальной линии.

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


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

1⃣Определите общую ширину стены, сложив ширины кирпичей в первом ряду. Создайте массив pos, где pos[i] указывает на текущую позицию в i-ом ряду.

2⃣Пройдите по каждой возможной позиции для вертикальной линии (от 1 до общей ширины стены - 1). Для каждой позиции обновите массив pos, проверяя, пересекает ли линия границу кирпича. Если пересекает, увеличьте значение pos[i].

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

😎 Решение:
public class Solution {
public int LeastBricks(IList<IList<int>> wall) {
int[] pos = new int[wall.Count];
int sum = 0, res = int.MaxValue;

foreach (int el in wall[0])
sum += el;

while (sum != 0) {
int count = 0;
for (int i = 0; i < wall.Count; i++) {
if (wall[i][pos[i]] != 0)
count++;
else
pos[i]++;
wall[i][pos[i]]--;
}
sum--;
res = Math.Min(res, count);
}

return res;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 984. String Without AAA or BBB
Сложность: medium

Даны два целых числа a и b, верните любую строку s, такую что:

s имеет длину a + b и содержит ровно a букв 'a' и ровно b букв 'b'.
Подстрока 'aaa' не встречается в s.
Подстрока 'bbb' не встречается в s.

Пример:
Input: a = 4, b = 1
Output: "aabaa"


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

1⃣Инициализация переменных:
Завести пустую строку s и переменные a_count и b_count для отслеживания оставшихся 'a' и 'b' соответственно.

2⃣Создание строки:
Добавляйте символы в строку s, попеременно добавляя 'a' и 'b', чтобы избегать подстрок 'aaa' и 'bbb'.
Если в строке подряд уже два символа 'a' и осталось ещё 'b', добавьте 'b' и наоборот.
Если оба символа возможны для добавления, выбирайте тот, которого осталось больше.

3⃣Добавление оставшихся символов:
После основной логики добавления символов, добавьте оставшиеся 'a' или 'b' в конец строки, если они остались.

😎 Решение:
public class Solution {
public string StrWithout3a3b(int a, int b) {
StringBuilder result = new StringBuilder();

while (a > 0 || b > 0) {
if (result.Length >= 2 && result[result.Length - 1] == result[result.Length - 2]) {
if (result[result.Length - 1] == 'a') {
result.Append('b');
b--;
} else {
result.Append('a');
a--;
}
} else {
if (a >= b) {
result.Append('a');
a--;
} else {
result.Append('b');
b--;
}
}
}

return result.ToString();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1229. Meeting Scheduler
Сложность: medium

Даны массивы доступных временных слотов slots1 и slots2 для двух человек и продолжительность встречи duration, верните самый ранний временной слот, который подходит обоим и имеет продолжительность duration.

Если нет общего временного слота, который удовлетворяет требованиям, верните пустой массив.

Формат временного слота — это массив из двух элементов [start, end], представляющий инклюзивный временной диапазон от start до end.

Гарантируется, что никакие два доступных временных слота одного и того же человека не пересекаются друг с другом. То есть для любых двух временных слотов [start1, end1] и [start2, end2] одного и того же человека либо start1 > end2, либо start2 > end1.

Пример:
Input: slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 8
Output: [60,68]


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

1⃣Отсортируйте оба массива slots1 и slots2 по времени начала.

2⃣Инициализируйте два указателя, указывающие на начало slots1 и slots2 соответственно.

3⃣Перебирайте, пока указатель1 не достигнет конца slots1 или указатель2 не достигнет конца slots2:
Найдите общий слот между slots1[pointer1] и slots2[pointer2].
Если общий слот больше или равен duration, верните результат.
В противном случае найдите слот, который заканчивается раньше, и передвиньте указатель.
Если общий слот не найден, верните пустой массив.

😎 Решение:
public class Solution {
public IList<int> MinAvailableDuration(int[][] slots1, int[][] slots2, int duration) {
Array.Sort(slots1, (a, b) => a[0].CompareTo(b[0]));
Array.Sort(slots2, (a, b) => a[0].CompareTo(b[0]));

int pointer1 = 0, pointer2 = 0;

while (pointer1 < slots1.Length && pointer2 < slots2.Length) {
int intersectLeft = Math.Max(slots1[pointer1][0], slots2[pointer2][0]);
int intersectRight = Math.Min(slots1[pointer1][1], slots2[pointer2][1]);

if (intersectRight - intersectLeft >= duration) {
return new List<int> { intersectLeft, intersectLeft + duration };
}

if (slots1[pointer1][1] < slots2[pointer2][1]) {
pointer1++;
} else {
pointer2++;
}
}
return new List<int>();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 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 (поиск в ширину) для определения результатов игры, начиная с конечных состояний и работая назад.

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

public class Solution {
public int CatMouseGame(int[][] graph) {
int n = graph.Length;
const int DRAW = 0, MOUSE = 1, CAT = 2;
int[,,] dp = new int[n, n, 2];
Queue<int[]> queue = new Queue<int[]>();

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.Enqueue(new int[] { 0, i, 0, MOUSE });
queue.Enqueue(new int[] { 0, i, 1, MOUSE });
queue.Enqueue(new int[] { i, i, 0, CAT });
queue.Enqueue(new int[] { i, i, 1, CAT });
}

while (queue.Count > 0) {
var state = queue.Dequeue();
int mouse = state[0], cat = state[1], turn = state[2], winner = state[3];
foreach (var parent in 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.Enqueue(new int[] { m, c, t, winner });
} else {
int degrees = 0;
foreach (var _ in Parents(graph, m, c, t)) degrees++;
if (degrees == 0) {
dp[m, c, t] = winner;
queue.Enqueue(new int[] { m, c, t, winner });
}
}
}
}
}

return dp[1, 2, 0];
}

private IEnumerable<int[]> Parents(int[][] graph, int mouse, int cat, int turn) {
if (turn == 1) {
foreach (int m in graph[mouse]) {
yield return new int[] { m, cat, 0 };
}
} else {
foreach (int c in graph[cat]) {
if (c > 0) yield return new int[] { mouse, c, 1 };
}
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1351. Count Negative Numbers in a Sorted Matrix
Сложность: easy

Дана матрица m x n grid, которая отсортирована по убыванию как по строкам, так и по столбцам. Вернуть количество отрицательных чисел в grid.

Пример:
Input: grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
Output: 8
Explanation: There are 8 negatives number in the matrix.


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

1⃣Инициализировать переменную count = 0 для подсчета общего числа отрицательных элементов в матрице.

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

3⃣Вернуть count.

😎 Решение:
public class Solution {
public int CountNegatives(int[][] grid) {
int count = 0;
foreach (var row in grid) {
foreach (var element in row) {
if (element < 0) {
count++;
}
}
}
return count;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 151. Reverse Words in a String
Сложность: medium

Дана входная строка s, переверните порядок слов.

Слово определяется как последовательность символов, не являющихся пробелами. Слова в строке s разделены как минимум одним пробелом.

Верните строку, в которой слова расположены в обратном порядке, соединённые одним пробелом.

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

Пример:
Input: s = "the sky is blue"
Output: "blue is sky the"


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

1⃣Удаление лишних пробелов:
Удалите начальные и конечные пробелы из строки s. Это делается для того, чтобы убрать пробелы в начале и в конце строки, которые могут исказить конечный результат. В коде это реализовано с помощью методов erase и find_first_not_of/find_last_not_of, которые удаляют пробелы до первого и после последнего непробельного символа.

2⃣Разделение строки на слова:
Преобразуйте строку s в поток и используйте istringstream для чтения слов, разделенных пробелами. Каждое слово определяется как последовательность символов, не содержащая пробелов. Слова сохраняются в вектор words. Это делается с помощью copy, который копирует слова из потока в words с помощью istream_iterator.

3⃣Реверсирование и соединение слов:
Переверните вектор слов и соедините их обратно в одну строку, разделяя слова одним пробелом. Для реверсирования используется функция reverse, а для соединения слов — ostringstream вместе с ostream_iterator. Слова объединяются таким образом, что между ними находится только один пробел, исключая лишние пробелы между словами.

😎 Решение:
public class Solution {
public string ReverseWords(string s) {
s = s.Trim();
string[] words = s.Split(new char[] { ' ' },
StringSplitOptions.RemoveEmptyEntries);
Array.Reverse(words);
return String.Join(" ", words);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 670. Maximum Swap
Сложность: medium

Дано целое число num. Вы можете поменять местами две цифры не более одного раза, чтобы получить число с наибольшим значением.

Верните число с наибольшим значением, которое можно получить.

Пример:
Input: num = 2736
Output: 7236
Explanation: Swap the number 2 and the number 7.


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

1⃣Сохраняем кандидатов как списки длины len(num). Для каждой пары позиций (i, j) выполняем обмен цифр, записываем кандидата, если он больше текущего ответа, затем возвращаем цифры обратно.

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

3⃣Возвращаем максимальное значение из всех кандидатов.

😎 Решение:
public class Solution {
public int MaximumSwap(int num) {
char[] A = num.ToString().ToCharArray();
char[] ans = (char[])A.Clone();
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 = (char[])A.Clone();
}
break;
}
}
A[j] = A[i];
A[i] = tmp;
}
}
return int.Parse(new string(ans));
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1233. Remove Sub-Folders from the Filesystem
Сложность: medium

Если дан список папок folder, верните папки после удаления всех вложенных папок в этих папках. Вы можете вернуть ответ в любом порядке. Если папка[i] находится внутри другой папки[j], она называется ее вложенной папкой. Формат пути - это одна или несколько скомбинированных строк вида: '/', за которой следует одна или несколько строчных английских букв. Например, "/leetcode" и "/leetcode/problems" являются допустимыми путями, а пустая строка и "/" - нет.

Пример:
Input: folder = ["/a","/a/b","/c/d","/c/d/e","/c/f"]
Output: ["/a","/c/d","/c/f"]


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

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

2⃣Фильтрация вложенных папок:
Будем использовать переменную для отслеживания текущей родительской папки.

3⃣При проходе по отсортированному списку проверим, является ли текущий путь вложенной папкой для отслеживаемой родительской папки. Если нет, обновим отслеживаемую папку и добавим ее в результирующий список.

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

public class Solution {
public IList<string> RemoveSubfolders(string[] folder) {
Array.Sort(folder);
List<string> result = new List<string>();
string parent = "";

foreach (var path in folder) {
if (parent == "" || !path.StartsWith(parent + "/")) {
parent = path;
result.Add(path);
}
}

return result;
}
}


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