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

Тесты t.iss.one/+nebTPWgpeGs1OWFi
Вопросы собесов t.iss.one/+sjKGQXl79ytkYzIy
Вакансии t.iss.one/+BQFHXZQ0zrViNGIy
Download Telegram
Задача: 1140. Stone Game II
Сложность: medium

Алиса и Боб продолжают свои игры с кучами камней. Есть несколько куч, расположенных в ряд, и в каждой куче положительное количество камней piles[i]. Цель игры - закончить с наибольшим количеством камней.
Алиса и Боб ходят по очереди, начиная с Алисы. Изначально M = 1.
В свой ход каждый игрок может взять все камни из первых X оставшихся куч, где 1 <= X <= 2M. Затем, мы устанавливаем M = max(M, X).
Игра продолжается до тех пор, пока все камни не будут взяты.
Предполагая, что Алиса и Боб играют оптимально, верните максимальное количество камней, которые может получить Алиса.

Пример:
Input: piles = [2,7,9,4,4]
Output: 10
Explanation: If Alice takes one pile at the beginning, Bob takes two piles, then Alice takes 2 piles again.
Alice can get 2 + 4 + 4 = 10 piles in total. If Alice takes two piles at the beginning, then Bob can take all three piles left.
In this case, Alice get 2 + 7 = 9 piles in total. So we return 10 since it's larger.


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

1⃣Создать рекурсивную функцию f, которая принимает три параметра: p (игрок), i (индекс текущей кучи),
и m (максимальное количество куч, которые можно взять за ход).
Если i равен длине массива кучи, вернуть 0 (базовый случай рекурсии). Если значение уже вычислено ранее (dp[p][i][m] != -1), вернуть его.

2⃣Инициализировать переменную s как количество камней, взятых текущим игроком за ход, и переменную res для хранения результата текущего состояния.
Если ход Боба, инициализировать res большим числом, так как Боб хочет минимизировать результат.
Если ход Алисы, инициализировать res маленьким числом, так как Алиса хочет максимизировать результат.

3⃣Итеративно обновлять значение res в зависимости от того, чей ход, и обновлять значения в dp[p][i][m]. В конце вернуть res.

😎 Решение:
public class Solution {
public int StoneGameII(int[] piles) {
int[][][] dp = new int[2][][];
for (int i = 0; i < 2; i++) {
dp[i] = new int[piles.Length + 1][];
for (int j = 0; j <= piles.Length; j++) {
dp[i][j] = new int[piles.Length + 1];
for (int k = 0; k <= piles.Length; k++) {
dp[i][j][k] = -1;
}
}
}

int f(int p, int i, int m) {
if (i == piles.Length) return 0;
if (dp[p][i][m] != -1) return dp[p][i][m];
int res = p == 1 ? 1000000 : -1;
int s = 0;
for (int x = 1; x <= Math.Min(2 * m, piles.Length - i); x++) {
s += piles[i + x - 1];
if (p == 0) {
res = Math.Max(res, s + f(1, i + x, Math.Max(m, x)));
} else {
res = Math.Min(res, f(0, i + x, Math.Max(m, x)));
}
}
return dp[p][i][m] = res;
}

return f(0, 0, 1);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1151. Minimum Swaps to Group All 1's Together
Сложность: medium

Дан бинарный массив data, необходимо вернуть минимальное количество перестановок, чтобы сгруппировать все 1, присутствующие в массиве, вместе в любом месте массива.

Пример:
Input: data = [1,0,1,0,1]
Output: 1
Explanation: There are 3 ways to group all 1's together:
[1,1,1,0,0] using 1 swap.
[0,1,1,1,0] using 2 swaps.
[0,0,1,1,1] using 1 swap.
The minimum is 1.


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

1⃣Используем два указателя, left и right, чтобы поддерживать скользящее окно длиной ones и проверяем каждый фрагмент массива data, подсчитывая количество единиц в нем (cnt_one) и запоминая максимальное значение max_one.

2⃣Пока окно скользит по массиву data, поддерживаем его длину равной ones.

3⃣Обновляем количество единиц в окне, добавляя новую границу data[right] и вычитая левую границу data[left].

😎 Решение:
public class Solution {
public int MinSwaps(int[] data) {
int ones = data.Sum();
int cnt_one = 0, max_one = 0;
int left = 0, right = 0;

while (right < data.Length) {
cnt_one += data[right++];
if (right - left > ones) {
cnt_one -= data[left++];
}
max_one = Math.Max(max_one, cnt_one);
}
return ones - max_one;
}
}


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

Сообщение, содержащее буквы от A-Z, может быть закодировано в цифры с помощью следующего отображения: 'A' -> "1" 'B' -> "2" ... 'Z' -> "26" Чтобы декодировать закодированное сообщение, все цифры должны быть сгруппированы, а затем снова преобразованы в буквы с помощью обратного отображения (может быть несколько способов). Например, "11106" может быть преобразовано в: "AAJF" с группировкой (1 1 10 6) "KJF" с группировкой (11 10 6) Обратите внимание, что группировка (1 11 06) недействительна, поскольку "06" не может быть преобразовано в "F", так как "6" отличается от "06". В дополнение к вышеуказанным преобразованиям кодированное сообщение может содержать символ "*", который может представлять любую цифру от "1" до "9" ("0" исключается). Например, кодированное сообщение "1*" может представлять любое из кодированных сообщений "11", "12", "13", "14", "15", "16", "17", "18" или "19". Декодирование "1*" эквивалентно декодированию любого из кодированных сообщений, которые оно может представлять. Если задана строка s, состоящая из цифр и символов '*', верните количество способов ее декодирования. Поскольку ответ может быть очень большим, верните его по модулю 109 + 7.

Пример:
Input: s = "*"
Output: 9


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

1⃣Инициализация
Создайте массив dp, где dp[i] представляет количество способов декодирования подстроки s[0:i]. Установите начальные значения dp[0] = 1 (пустая строка имеет один способ декодирования).

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

3⃣Модульное вычисление
Поскольку количество способов декодирования может быть большим, вычисляйте результаты по модулю 10^9 + 7.

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

public class Solution {
public int NumDecodings(string s) {
const int MOD = 1000000007;
int n = s.Length;
long[] dp = new long[n + 1];
dp[0] = 1;

for (int i = 1; i <= n; i++) {
if (s[i - 1] == '*') {
dp[i] = 9 * dp[i - 1];
} else if (s[i - 1] != '0') {
dp[i] = dp[i - 1];
}

if (i > 1) {
if (s[i - 2] == '*') {
if (s[i - 1] == '*') {
dp[i] += 15 * dp[i - 2];
} else if (s[i - 1] <= '6') {
dp[i] += 2 * dp[i - 2];
} else {
dp[i] += dp[i - 2];
}
} else if (s[i - 2] == '1') {
if (s[i - 1] == '*') {
dp[i] += 9 * dp[i - 2];
} else {
dp[i] += dp[i - 2];
}
} else if (s[i - 2] == '2') {
if (s[i - 1] == '*') {
dp[i] += 6 * dp[i - 2];
} else if (s[i - 1] <= '6') {
dp[i] += dp[i - 2];
}
}
}

dp[i] %= MOD;
}

return (int)dp[n];
}
}


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

На лимонадной стойке каждый лимонад стоит $5. Покупатели стоят в очереди, чтобы купить лимонад, и заказывают по одному (в порядке, указанном в массиве bills). Каждый покупатель покупает только один лимонад и платит либо $5, $10, либо $20. Вы должны предоставить правильную сдачу каждому покупателю, чтобы чистая сделка была такой, что покупатель платит $5.

Обратите внимание, что изначально у вас нет никакой сдачи.

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

Пример:
Input: bills = [5,5,5,10,20]
Output: true
Explanation:
From the first 3 customers, we collect three $5 bills in order.
From the fourth customer, we collect a $10 bill and give back a $5.
From the fifth customer, we give a $10 bill and a $5 bill.
Since all customers got correct change, we output true.


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

1⃣Инициализируем переменные для хранения количества пятерок и десяток. Если покупатель платит $5, добавляем эту купюру в наш запас.

2⃣Если покупатель платит $10, проверяем наличие пятерки для сдачи. Если пятерки нет, возвращаем false. В противном случае, уменьшаем количество пятерок и увеличиваем количество десяток.

3⃣Если покупатель платит $20, сначала пытаемся дать сдачу десяткой и пятеркой. Если это невозможно, проверяем наличие трех пятерок. Если не можем дать сдачу, возвращаем false. После обработки всех покупателей, возвращаем true.

😎 Решение:
public class Solution {
public bool LemonadeChange(int[] bills) {
int five = 0, ten = 0;
foreach (var bill in bills) {
if (bill == 5) {
five++;
} else if (bill == 10) {
if (five == 0) return false;
five--;
ten++;
} else {
if (five > 0 && ten > 0) {
five--;
ten--;
} else if (five >= 3) {
five -= 3;
} else {
return false;
}
}
}
return true;
}
}


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

Решите заданное уравнение и верните значение 'x' в виде строки "x=#value". Уравнение содержит только операции '+', '-', переменную 'x' и ее коэффициент. Вы должны вернуть "No solution", если для уравнения нет решения, или "Infinite solutions", если для уравнения существует бесконечное количество решений. Если для уравнения существует ровно одно решение, мы убеждаемся, что значение 'x' является целым числом.

Пример:
Input: s = "*"
Output: 9


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

1⃣Разделение уравнения
Разделите уравнение на левую и правую части относительно знака равенства '='.

2⃣Парсинг и упрощение
Пройдитесь по каждой части уравнения, упрощая ее до суммы коэффициентов 'x' и числовых значений.

3⃣Решение уравнения
Используйте уравнение вида ax + b = cx + d, чтобы решить для 'x'. Если коэффициенты 'x' равны и числовые значения равны, уравнение имеет бесконечное количество решений. Если коэффициенты 'x' равны, но числовые значения различны, решения нет. В противном случае вычислите значение 'x'.

😎 Решение:
using System;
using System.Text.RegularExpressions;

public class Solution {
public string SolveEquation(string equation) {
string[] sides = equation.Split('=');
int[] left = Parse(sides[0]);
int[] right = Parse(sides[1]);

int coeff = left[0] - right[0];
int constPart = right[1] - left[1];

if (coeff == 0) {
return constPart == 0 ? "Infinite solutions" : "No solution";
}
return "x=" + (constPart / coeff);
}

private int[] Parse(string s) {
int coeff = 0, constPart = 0, sign = 1, num = 0;
int i = 0;
while (i < s.Length) {
if (s[i] == '+') {
sign = 1;
i++;
} else if (s[i] == '-') {
sign = -1;
i++;
} else if (char.IsDigit(s[i])) {
num = 0;
while (i < s.Length && char.IsDigit(s[i])) {
num = num * 10 + (s[i] - '0');
i++;
}
if (i < s.Length && s[i] == 'x') {
coeff += sign * num;
i++;
} else {
constPart += sign * num;
}
} else if (s[i] == 'x') {
coeff += sign;
i++;
}
}
return new int[]{coeff, constPart};
}
}


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

Реализуйте базовый калькулятор для вычисления простого строкового выражения.

Строка выражения содержит только неотрицательные целые числа, операторы '+', '-', '*', '/' и открывающие '(' и закрывающие скобки ')'. Целочисленное деление должно округляться к нулю.

Предполагается, что данное выражение всегда корректно. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].

Примечание: нельзя использовать встроенные функции для вычисления строк как математических выражений, такие как eval().

Пример:
Input: s = "1+1"
Output: 2


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

1⃣Определите вспомогательную функцию evaluate, которая принимает оператор и числовые аргументы. Заметьте, что эта функция идентична той, что представлена в подходе "Basic Calculator II". Инициализируйте несколько переменных: стек для хранения промежуточных результатов, curr для отслеживания текущего числа, которое мы строим, и previousOperator для отслеживания предыдущего оператора. Добавьте в строку s случайный символ, который не будет появляться во входных данных, например "@".

2⃣Итерация по входным данным. Для каждого символа c: если c является цифрой, добавьте его к curr. В противном случае, если c == '(', мы начинаем вычисление нового изолированного выражения. В этом случае сохраните previousOperator в стек и установите previousOperator = "+".

3⃣Если c является оператором, то необходимо вычислить значение curr. Используйте функцию evaluate, чтобы применить previousOperator к curr, и добавьте результат в стек. Затем сбросьте curr до нуля и обновите previousOperator = c. Если c == ')', это означает, что мы находимся в конце изолированного выражения и должны полностью его вычислить. Извлекайте из стека до тех пор, пока не достигнете оператора, суммируя все извлеченные числа в curr. Как только достигнете оператора, обновите previousOperator = stack.pop(). Верните сумму всех чисел в стеке.

😎 Решение:
public class Solution {
private string Evaluate(char operator, string first, string second) {
int x = int.Parse(first);
int y = int.Parse(second);
int res = 0;

if (operator == '+') {
res = x;
} else if (operator == '-') {
res = -x;
} else if (operator == '*') {
res = x * y;
} else {
res = x / y;
}

return res.ToString();
}

public int Calculate(string s) {
Stack<string> stack = new Stack<string>();
string curr = "";
char previousOperator = '+';
s += "@";
HashSet<string> operators = new HashSet<string>(new string[] {"+", "-", "*", "/"});

foreach (char c in s) {
if (char.IsDigit(c)) {
curr += c;
} else if (c == '(') {
stack.Push(previousOperator.ToString());
previousOperator = '+';
} else {
if (previousOperator == '*' || previousOperator == '/') {
stack.Push(Evaluate(previousOperator, stack.Pop(), curr));
} else {
stack.Push(Evaluate(previousOperator, curr, "0"));
}

curr = "";
previousOperator = c;
if (c == ')') {
int currentTerm = 0;
while (!operators.Contains(stack.Peek())) {
currentTerm += int.Parse(stack.Pop());
}

curr = currentTerm.ToString();
previousOperator = stack.Pop()[0];
}
}
}

int ans = 0;
foreach (string num in stack) {
ans += int.Parse(num);
}

return ans;
}
}


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

Бинарные часы имеют 4 светодиода сверху для представления часов (0-11) и 6 светодиодов снизу для представления минут (0-59). Каждый светодиод представляет ноль или единицу, при этом младший разряд находится справа.

Пример:
Input: turnedOn = 1
Output: ["0:01","0:02","0:04","0:08","0:16","0:32","1:00","2:00","4:00","8:00"]


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

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

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

3⃣Форматирование результата:
Если комбинация часов и минут соответствует условию, отформатируйте их в виде строки "часы:минуты" и добавьте в список результатов.

😎 Решение:
public class Solution {
public IList<string> ReadBinaryWatch(int turnedOn) {
var results = new List<string>();
for (int h = 0; h < 12; h++) {
for (int m = 0; m < 60; m++) {
if (CountBits(h) + CountBits(m) == turnedOn) {
results.Add($"{h}:{m:D2}");
}
}
}
return results;
}

private int CountBits(int n) {
int count = 0;
while (n > 0) {
count += n & 1;
n >>= 1;
}
return count;
}
}


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

Дано массив уникальных строк words, верните минимально возможные сокращения для каждого слова.

Правила сокращения строки следующие:
Первоначальное сокращение для каждого слова: первый символ, затем количество символов между первым и последним символом, затем последний символ.
Если более одного слова имеют одинаковое сокращение, выполните следующее:
Увеличьте префикс (символы в первой части) каждого из их сокращений на 1.
Например, начнем с слов ["abcdef", "abndef"], оба изначально сокращены как "a4f". Последовательность операций будет следующей: ["a4f", "a4f"] -> ["ab3f", "ab3f"] -> ["abc2f", "abn2f"].
Эта операция повторяется до тех пор, пока каждое сокращение не станет уникальным.
В конце, если сокращение не сделало слово короче, оставьте его в исходном виде.

Пример:
Input: words = ["like","god","internal","me","internet","interval","intension","face","intrusion"]
Output: ["l2e","god","internal","me","i6t","interval","inte4n","f2e","intr4n"]


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

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

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

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

😎 Решение:
public class Solution {
public IList<string> WordsAbbreviation(IList<string> words) {
int n = words.Count;
string[] ans = new string[n];
int[] prefix = new int[n];

for (int i = 0; i < n; ++i)
ans[i] = Abbrev(words[i], 0);

for (int i = 0; i < n; ++i) {
while (true) {
HashSet<int> dupes = new HashSet<int>();
for (int j = i + 1; j < n; ++j) {
if (ans[i] == ans[j])
dupes.Add(j);
}

if (dupes.Count == 0) break;
dupes.Add(i);
foreach (int k in dupes)
ans[k] = Abbrev(words[k], ++prefix[k]);
}
}

return ans.ToList();
}

private string Abbrev(string word, int i) {
int n = word.Length;
if (n - i <= 3) return word;
return word.Substring(0, i + 1) + (n - i - 2) + word[n - 1];
}
}


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

Дана бинарная матрица размером rows x cols, заполненная 0 и 1. Найдите наибольший прямоугольник, содержащий только 1, и верните его площадь.

Пример:
Input: matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
Output: 6
Explanation: The maximal rectangle is shown in the above picture.


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

1⃣Вычисление максимальной ширины прямоугольника для каждой координаты: Для каждой ячейки в каждой строке сохраняем количество последовательных единиц. При прохождении по строке обновляем максимально возможную ширину в этой точке, используя формулу row[i] = row[i - 1] + 1, если row[i] == '1'.

2⃣Определение максимальной площади прямоугольника с нижним правым углом в данной точке: При итерации вверх по столбцу максимальная ширина прямоугольника от исходной точки до текущей точки является минимальным значением среди всех максимальных ширин, с которыми мы сталкивались. Используем формулу maxWidth = min(maxWidth, widthHere) и curArea = maxWidth * (currentRow - originalRow + 1), затем обновляем maxArea = max(maxArea, curArea).

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

😎 Решение:
public class Solution {
public int MaximalRectangle(char[][] matrix) {
if (matrix.Length == 0)
return 0;
int maxarea = 0;
int[][] dp = new int [matrix.Length][];
for (int a = 0; a < dp.Length; a++) dp[a] = new int[matrix[0].Length];
for (int i = 0; i < matrix.Length; i++) {
for (int j = 0; j < matrix[0].Length; j++) {
if (matrix[i][j] == '1') {
dp[i][j] = j == 0 ? 1 : dp[i][j - 1] + 1;
int width = dp[i][j];
for (int k = i; k >= 0; k--) {
width = Math.Min(width, dp[k][j]);
maxarea = Math.Max(maxarea, width * (i - k + 1));
}
}
}
}

return maxarea;
}
}


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

Дан указатель на начало связного списка, поверните список вправо на k позиций.

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


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

1⃣Найдите старый хвост и соедините его с головой (old_tail.next = head), чтобы замкнуть кольцо. Одновременно вычислите длину списка n.

2⃣Найдите новый хвост, который находится на позиции (n - k % n - 1) от головы, и новую голову, которая находится на позиции (n - k % n).

3⃣Разорвите кольцо (new_tail.next = None) и верните new_head.

😎 Решение:
public class Solution {
public ListNode RotateRight(ListNode head, int k) {
if (head == null)
return null;
if (head.next == null)
return head;

ListNode old_tail = head;
int n;
for (n = 1; old_tail.next != null; n++) old_tail = old_tail.next;
old_tail.next = head;

ListNode new_tail = head;
for (int i = 0; i < n - k % n - 1; i++) new_tail = new_tail.next;
ListNode new_head = new_tail.next;

new_tail.next = null;
return new_head;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: №21. Merge Two Sorted Lists
Сложность: easy

Вам даны заголовки двух отсортированных связанных списков list1 и list2. Объедините два списка в один отсортированный список. Список должен быть составлен путем сращивания узлов первых двух списков. Верните заголовок объединенного связанного списка.

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


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

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

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

3⃣Если один из списков закончился, добавить оставшиеся узлы другого списка.

😎 Решение:
public class Solution {
public ListNode MergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode current = dummy;

while (list1 != null && list2 != null) {
if (list1.val <= list2.val) {
current.next = list1;
list1 = list1.next;
} else {
current.next = list2;
list2 = list2.next;
}
current = current.next;
}

current.next = list1 ?? list2;
return dummy.next;
}
}


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

Совершенное число — это положительное целое число, которое равно сумме своих положительных делителей, исключая само число. Делитель целого числа x — это целое число, которое может делить x нацело.

Дано целое число n, верните true, если n является совершенным числом, в противном случае верните false.

Пример:
Input: num = 28
Output: true
Explanation: 28 = 1 + 2 + 4 + 7 + 14
1, 2, 4, 7, and 14 are all divisors of 28.


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

1⃣Инициализация
Если число num меньше или равно 0, вернуть false. Инициализируйте переменную sum значением 0.

2⃣Поиск делителей и вычисление суммы
Переберите числа от 1 до квадратного корня num. Если число является делителем num, добавьте его к sum. Если делитель не равен квадратному корню num, добавьте к sum также результат деления num на делитель.

3⃣Проверка на совершенное число
Вычтите num из sum. Если результат равен num, вернуть true, иначе вернуть false.

😎 Решение:
public class Solution {
public bool CheckPerfectNumber(int num) {
if (num <= 0) return false;
int sum = 0;
for (int i = 1; i * i <= num; i++) {
if (num % i == 0) {
sum += i;
if (i * i != num) {
sum += num / i;
}
}
}
return sum - num == num;
}
}


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

Если задана строка num, представляющая неотрицательное целое число num, и целое число k, верните наименьшее возможное целое число после удаления k цифр из num.

Пример:
Input: num = "1432219", k = 3
Output: "1219"


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

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

2⃣Обработка каждой цифры:
Перебирайте каждую цифру в строке num.
Если текущая цифра меньше верхней цифры в стеке и у вас есть еще возможность удалить цифры (k > 0), удалите верхнюю цифру из стека.
Добавьте текущую цифру в стек.
Удаление оставшихся цифр:
Если после прохождения всей строки k еще больше нуля, удалите оставшиеся цифры из конца стека

3⃣Формирование результата:
Постройте итоговое число из цифр в стеке и удалите ведущие нули.

😎 Решение:
public class Solution {
public string RemoveKdigits(string num, int k) {
Stack<char> stack = new Stack<char>();
foreach (char digit in num) {
while (k > 0 && stack.Count > 0 && stack.Peek() > digit) {
stack.Pop();
k--;
}
stack.Push(digit);
}
char[] resultArray = stack.ToArray();
Array.Reverse(resultArray);
string result = new string(resultArray).Substring(0, resultArray.Length - k).TrimStart('0');
return result == "" ? "0" : result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 760. Find Anagram Mappings
Сложность: easy

Вам даны два целочисленных массива nums1 и nums2, где nums2 - анаграмма nums1. Оба массива могут содержать дубликаты. Верните индексное отображение массива mapping из nums1 в nums2, где mapping[i] = j означает, что i-й элемент в nums1 появляется в nums2 по индексу j. Если ответов несколько, верните любой из них. Массив a является анаграммой массива b означает, что b создается путем случайного изменения порядка элементов в a.

Пример:
Input: nums1 = [12,28,46,32,50], nums2 = [50,12,32,46,28]
Output: [1,4,3,2,0]


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

1⃣Создайте словарь для хранения индексов элементов в nums2.

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

3⃣Верните массив индексов.

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

public class Solution {
public int[] AnagramMapping(int[] nums1, int[] nums2) {
var indexMap = new Dictionary<int, List<int>>();
for (int i = 0; i < nums2.Length; i++) {
if (!indexMap.ContainsKey(nums2[i])) {
indexMap[nums2[i]] = new List<int>();
}
indexMap[nums2[i]].Add(i);
}

var mapping = new int[nums1.Length];
for (int i = 0; i < nums1.Length; i++) {
var indices = indexMap[nums1[i]];
mapping[i] = indices[indices.Count - 1];
indices.RemoveAt(indices.Count - 1);
}

return mapping;
}
}


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

Дан корень бинарного дерева. Верните то же дерево, в котором удалены все поддеревья (данного дерева), не содержащие 1.

Поддерево узла node - это сам узел node и все узлы, являющиеся потомками node.

Пример:
Input: root = [1,null,0,0,1]
Output: [1,null,0,null,1]
Explanation:
Only the red nodes satisfy the property "every subtree not containing a 1".
The diagram on the right represents the answer.


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

1⃣Используем функцию containsOne(node), которая сообщает, содержит ли поддерево в данном узле единицу, и обрезает все поддеревья, не содержащие единицу.

2⃣Например, если поддерево node.left не содержит единицу, то мы должны обрезать его через node.left = null.

3⃣Также нужно проверить родительский узел. Например, если дерево состоит из одного узла 0, то ответом будет пустое дерево.

😎 Решение:
public class TreeNode {
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val = 0, TreeNode left = null, TreeNode right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}

public class Solution {
public TreeNode PruneTree(TreeNode root) {
return ContainsOne(root) ? root : null;
}

private bool ContainsOne(TreeNode node) {
if (node == null) return false;

bool leftContainsOne = ContainsOne(node.left);
bool rightContainsOne = ContainsOne(node.right);

if (!leftContainsOne) node.left = null;
if (!rightContainsOne) node.right = null;

return node.val == 1 || leftContainsOne || rightContainsOne;
}
}


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

Числа Фибоначчи, обычно обозначаемые как F(n), образуют последовательность, называемую последовательностью Фибоначчи, так что каждое число является суммой двух предыдущих, начиная с 0 и 1. То есть,

F(0) = 0, F(1) = 1
F(n) = F(n - 1) + F(n - 2), для n > 1.
Дано n, вычислите F(n).

Пример:
Input: n = 3
Output: 2
Explanation: F(3) = F(2) + F(1) = 1 + 1 = 2.


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

1⃣Проверка начального условия
Если N <= 1, вернуть N.

2⃣Инициализация переменных
Инициализируйте current значением 0. Инициализируйте prev1 значением 1, что будет представлять fib(N-1) при вычислении текущего значения. Инициализируйте prev2 значением 0, что будет представлять fib(N-2) при вычислении текущего значения.

3⃣Итерация и вычисление
Итерация от 2 до N включительно. На каждой итерации: установите current как сумму prev1 и prev2. Обновите prev2 значением prev1. Обновите prev1 значением current. Вернуть значение current после завершения итерации.

😎 Решение:
public class Solution {
public int Fib(int N) {
if (N <= 1) return N;
int current = 0, prev1 = 1, prev2 = 0;
for (int i = 2; i <= N; i++) {
current = prev1 + prev2;
prev2 = prev1;
prev1 = current;
}
return current;
}
}


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

Вам дается несколько журналов, где каждый журнал содержит уникальный идентификатор и временную метку. Временная метка - это строка, имеющая следующий формат: Год:Месяц:День:Час:Минута:Секунда, например, 2017:01:01:23:59:59. Все домены - десятичные числа с нулевым добавлением. Реализация класса LogSystem: LogSystem() Инициализирует объект LogSystem. void put(int id, string timestamp) Сохраняет заданный журнал (id, timestamp) в вашей системе хранения.
int[] retrieve(string start, string end, string granularity) Возвращает идентификаторы журналов, временные метки которых находятся в диапазоне от start до end включительно. start и end имеют тот же формат, что и timestamp, а granularity означает, насколько точным должен быть диапазон (т. е. с точностью до дня, минуты и т. д.). Например, start = "2017:01:01:23:59:59", end = "2017:01:02:23:59:59", а granularity = "Day" означает, что нам нужно найти журналы в диапазоне от 1 января 2017 года до 2 января 2017 года включительно, а час, минуту и секунду для каждой записи журнала можно игнорировать.

Пример:
Input
["LogSystem", "put", "put", "put", "retrieve", "retrieve"]
[[], [1, "2017:01:01:23:59:59"], [2, "2017:01:01:22:59:59"], [3, "2016:01:01:00:00:00"], ["2016:01:01:01:01:01", "2017:01:01:23:00:00", "Year"], ["2016:01:01:01:01:01", "2017:01:01:23:00:00", "Hour"]]
Output
[null, null, null, null, [3, 2, 1], [2, 1]]


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

1⃣Инициализация и хранение журналов
Реализуйте метод put, который будет сохранять журнал с заданным id и timestamp в системе хранения.

2⃣Формирование диапазона
Реализуйте метод retrieve, который будет формировать диапазон временных меток на основе заданного start, end и granularity.

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

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

public class LogSystem {
private List<LogEntry> logs;

public LogSystem() {
logs = new List<LogEntry>();
}

public void Put(int id, string timestamp) {
logs.Add(new LogEntry(id, timestamp));
}

public IList<int> Retrieve(string start, string end, string granularity) {
int index = GetGranularityIndex(granularity);
string startPrefix = start.Substring(0, index);
string endPrefix = end.Substring(0, index);

List<int> result = new List<int>();
foreach (var log in logs) {
string timestampPrefix = log.Timestamp.Substring(0, index);
if (startPrefix.CompareTo(timestampPrefix) <= 0 && timestampPrefix.CompareTo(endPrefix) <= 0) {
result.Add(log.Id);
}
}
return result;
}

private int GetGranularityIndex(string granularity) {
switch (granularity) {
case "Year": return 4;
case "Month": return 7;
case "Day": return 10;
case "Hour": return 13;
case "Minute": return 16;
case "Second": return 19;
default: return 19;
}
}

private class LogEntry {
public int Id { get; }
public string Timestamp { get; }

public LogEntry(int id, string timestamp) {
Id = id;
Timestamp = timestamp;
}
}
}


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

Нам дан массив asteroids, состоящий из целых чисел, представляющих астероиды в ряд. Для каждого астероида абсолютное значение обозначает его размер, а знак - направление движения (положительное - вправо, отрицательное - влево). Каждый астероид движется с одинаковой скоростью. Определите состояние астероидов после всех столкновений. Если два астероида столкнутся, меньший из них взорвется. Если оба одинакового размера, то взорвутся оба. Два астероида, движущиеся в одном направлении, никогда не встретятся.

Пример:
Input: expression = "(let x 2 (mult x (let x 3 y 4 (add x y))))"
Output: 14


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

1⃣Определите функцию для оценки выражений.

2⃣Используйте рекурсивный подход для обработки различных типов выражений (let, add, mult, и переменных).

3⃣Используйте словарь для отслеживания значений переменных с учетом области видимости.

😎 Решение:
public class Solution {
public int Evaluate(string expression) {
return Evaluate(expression, new Dictionary<string, int>());
}

private int Evaluate(string expression, Dictionary<string, int> env) {
if (expression[0] != '(') {
return int.TryParse(expression, out var result) ? result : env[expression];
}

var tokens = Tokenize(expression);
if (tokens[0] == "let") {
for (int i = 1; i < tokens.Count - 2; i += 2) {
env[tokens[i]] = Evaluate(tokens[i + 1], env);
}
return Evaluate(tokens[^1], env);
} else if (tokens[0] == "add") {
return Evaluate(tokens[1], env) + Evaluate(tokens[2], env);
} else if (tokens[0] == "mult") {
return Evaluate(tokens[1], env) * Evaluate(tokens[2], env);
}
return 0;
}

private List<string> Tokenize(string expression) {
var tokens = new List<string>();
var token = string.Empty;
int parens = 0;
foreach (var c in expression) {
if (c == '(') {
parens++;
if (parens == 1) continue;
} else if (c == ')') {
parens--;
if (parens == 0) {
tokens.AddRange(Tokenize(token));
token = string.Empty;
continue;
}
} else if (c == ' ' && parens == 1) {
if (!string.IsNullOrEmpty(token)) {
tokens.Add(token);
token = string.Empty;
}
continue;
}
token += c;
}
if (!string.IsNullOrEmpty(token)) {
tokens.Add(token);
}
return tokens;
}
}


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

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

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


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

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

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

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

😎 Решение:
public class Solution {
public int[] BeautifulArray(int n) {
return Construct(n).ToArray();
}

private List<int> Construct(int n) {
if (n == 1) return new List<int> { 1 };
var odd = Construct((n + 1) / 2).Select(x => 2 * x - 1).ToList();
var even = Construct(n / 2).Select(x => 2 * x).ToList();
odd.AddRange(even);
return odd;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1274. Number of Ships in a Rectangle
Сложность: hard

(Эта задача является интерактивной.) Каждый корабль находится в целочисленной точке моря, представленной картезианской плоскостью, и каждая целочисленная точка может содержать не более 1 корабля. У вас есть функция Sea.hasShips(topRight, bottomLeft), которая принимает две точки в качестве аргументов и возвращает true, если в прямоугольнике, представленном этими двумя точками, есть хотя бы один корабль, включая на границе. Учитывая две точки: правый верхний и левый нижний углы прямоугольника, верните количество кораблей в этом прямоугольнике. Гарантируется, что в прямоугольнике находится не более 10 кораблей. Решения, содержащие более 400 обращений к hasShips, будут оцениваться как "Неправильный ответ". Кроме того, любые решения, пытающиеся обойти судью, приведут к дисквалификации.

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


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

1⃣Разделите текущий прямоугольник на четыре меньших прямоугольника

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

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

😎 Решение:
public class Solution {
public int CountShips(Sea sea, Point topRight, Point bottomLeft) {
if (!sea.HasShips(topRight, bottomLeft)) {
return 0;
}
if (topRight.x == bottomLeft.x && topRight.y == bottomLeft.y) {
return 1;
}
int midX = (topRight.x + bottomLeft.x) / 2;
int midY = (topRight.y + bottomLeft.y) / 2;
return CountShips(sea, new Point(midX, midY), bottomLeft) +
CountShips(sea, topRight, new Point(midX + 1, midY + 1)) +
CountShips(sea, new Point(midX, topRight.y), new Point(bottomLeft.x, midY + 1)) +
CountShips(sea, new Point(topRight.x, midY), new Point(midX + 1, bottomLeft.y));
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1005. Maximize Sum Of Array After K Negations
Сложность: easy

Учитывая целочисленный массив nums и целое число k, измените массив следующим образом: выберите индекс i и замените nums[i] на -nums[i]. Вы должны применить этот процесс ровно k раз. Вы можете выбрать один и тот же индекс i несколько раз. Верните наибольшую возможную сумму массива после его модификации таким образом.

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


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

1⃣Сортировка массива:
Отсортируйте массив nums по возрастанию, чтобы наибольшее количество раз менять самые маленькие (отрицательные) значения на их противоположные.

2⃣Модификация массива:
Пройдитесь по отсортированному массиву и замените k наименьших значений на их противоположные (умножьте на -1). Если встретите 0, прекратите дальнейшие изменения, так как изменение 0 на -0 не имеет смысла.

3⃣Проверка остатка изменений:
Если после первого прохода остались изменения (k нечетное), то найдите минимальное значение в измененном массиве и еще раз поменяйте его знак. Это обеспечит максимальную сумму.

😎 Решение:
public class Solution {
public int LargestSumAfterKNegations(int[] nums, int k) {
Array.Sort(nums);

for (int i = 0; i < nums.Length; i++) {
if (k > 0 && nums[i] < 0) {
nums[i] = -nums[i];
k--;
}
}

if (k % 2 == 1) {
Array.Sort(nums);
nums[0] = -nums[0];
}

return nums.Sum();
}
}


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