C# | LeetCode
3.48K subscribers
159 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
Задача: 380. Insert Delete GetRandom O(1)
Сложность: medium

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

RandomizedSet(): Инициализирует объект RandomizedSet.
bool insert(int val): Вставляет элемент val в множество, если его там нет. Возвращает true, если элемент отсутствовал, и false в противном случае.
bool remove(int val): Удаляет элемент val из множества, если он присутствует. Возвращает true, если элемент присутствовал, и false в противном случае.
int getRandom(): Возвращает случайный элемент из текущего множества элементов (гарантируется, что по крайней мере один элемент существует при вызове этого метода). Каждый элемент должен иметь равную вероятность быть возвращенным.
Вы должны реализовать функции класса таким образом, чтобы каждая функция работала в среднем за O(1) по времени.

Пример:
Input
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]


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

1⃣Создать словарь для хранения значений и их индексов, а также список для хранения значений.

2⃣Метод insert(val): Проверить наличие значения в словаре. Если отсутствует, добавить значение в список и обновить словарь с новым индексом.
Метод remove(val): Проверить наличие значения в словаре. Если присутствует, заменить удаляемое значение последним элементом списка, обновить его индекс в словаре, удалить последний элемент из списка и удалить значение из словаря.

3⃣Метод getRandom(): Возвращать случайный элемент из списка, используя встроенную функцию генерации случайных чисел.

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

public class RandomizedSet {
private Dictionary<int, int> dict;
private List<int> list;
private Random rand;

public RandomizedSet() {
dict = new Dictionary<int, int>();
list = new List<int>();
rand = new Random();
}

public bool Insert(int val) {
if (dict.ContainsKey(val)) {
return false;
}
dict[val] = list.Count;
list.Add(val);
return true;
}

public bool Remove(int val) {
if (!dict.ContainsKey(val)) {
return false;
}
int index = dict[val];
int lastElement = list[list.Count - 1];
list[index] = lastElement;
dict[lastElement] = index;
list.RemoveAt(list.Count - 1);
dict.Remove(val);
return true;
}

public int GetRandom() {
return list[rand.Next(list.Count)];
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1217. Minimum Cost to Move Chips to The Same Position
Сложность: easy

У нас есть n фишек, где позиция i-й фишки равна position[i].

Нам нужно переместить все фишки в одну и ту же позицию. За один шаг мы можем изменить позицию i-й фишки с position[i] на:
position[i] + 2 или position[i] - 2 с затратами = 0.
position[i] + 1 или position[i] - 1 с затратами = 1.
Верните минимальные затраты, необходимые для перемещения всех фишек в одну и ту же позицию.

Пример:
Input: position = [2,2,2,3,3]
Output: 2
Explanation: We can move the two chips at position 3 to position 2. Each move has cost = 1. The total cost = 2.


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

1⃣Посчитать количество фишек на четных и нечетных позициях.

2⃣Сравнить количество фишек на четных и нечетных позициях.

3⃣Вернуть минимальное количество фишек как минимальную стоимость для перемещения всех фишек в одну позицию.

😎 Решение:
public class Solution {
public int MinCostToMoveChips(int[] position) {
int evenCount = 0;
int oddCount = 0;

foreach (int pos in position) {
if (pos % 2 == 0) {
evenCount++;
} else {
oddCount++;
}
}

return Math.Min(evenCount, oddCount);
}
}


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

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

Геометрическая информация о каждом здании задана в массиве buildings, где buildings[i] = [lefti, righti, heighti]:

lefti — это координата x левого края i-го здания.
righti — это координата x правого края i-го здания.
heighti — это высота i-го здания.
Вы можете предположить, что все здания — это идеальные прямоугольники, стоящие на абсолютно плоской поверхности на высоте 0.

Пример:
Input: buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
Output: [[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
Explanation:
Figure A shows the buildings of the input.
Figure B shows the skyline formed by those buildings. The red points in figure B represent the key points in the output list.


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

1⃣Соберите все уникальные позиции для левых и правых краев зданий в массиве buildings и сохраните их в список edgeSet. Инициализируйте хэш-таблицу edgeIndexMap для хранения соответствующих индексов и значений элементов из heights.

2⃣Пройдитесь по всем зданиям в массиве buildings, найдите индексы их левого и правого краев, а также их высоту. Для каждого здания обновите максимальную высоту в диапазоне [leftIndex, rightIndex).

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

😎 Решение:
public class Solution {
public IList<IList<int>> GetSkyline(int[][] buildings) {
var edgeSet = new SortedSet<int>();
foreach (var building in buildings) {
edgeSet.Add(building[0]);
edgeSet.Add(building[1]);
}
var edges = edgeSet.ToList();
var edgeIndexMap = new Dictionary<int, int>();
for (int i = 0; i < edges.Count; ++i) {
edgeIndexMap[edges[i]] = i;
}
var heights = new int[edges.Count];
foreach (var building in buildings) {
int left = building[0], right = building[1], height = building[2];
int leftIndex = edgeIndexMap[left], rightIndex = edgeIndexMap[right];
for (int idx = leftIndex; idx < rightIndex; ++idx) {
heights[idx] = Math.Max(heights[idx], height);
}
}
var answer = new List<IList<int>>();
for (int i = 0; i < heights.Length; ++i) {
int currHeight = heights[i], currPos = edges[i];
if (answer.Count == 0 || answer[answer.Count - 1][1] != currHeight) {
answer.Add(new List<int> { currPos, currHeight });
}
}
return answer;
}
}


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

Если в строках s1 и s2 нет такого окна, которое покрывало бы все символы в s2, верните пустую строку "". Если таких окон минимальной длины несколько, возвращается окно с самым левым начальным индексом.

Пример:
Input: s1 = "abcdebdde", s2 = "bde"
Output: "bcde"


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

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

2⃣Поддерживайте счетчики для символов в текущем окне и требуемых символов из s2.

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

😎 Решение:
public class Solution {
public string MinWindow(string s1, string s2) {
if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2)) {
return "";
}

var dictT = new Dictionary<char, int>();
foreach (char c in s2) {
if (dictT.ContainsKey(c)) {
dictT[c]++;
} else {
dictT[c] = 1;
}
}

int required = dictT.Count;
int l = 0, r = 0, formed = 0;
var windowCounts = new Dictionary<char, int>();
int[] ans = { int.MaxValue, 0, 0 };

while (r < s1.Length) {
char c = s1[r];
if (windowCounts.ContainsKey(c)) {
windowCounts[c]++;
} else {
windowCounts[c] = 1;
}

if (dictT.ContainsKey(c) && windowCounts[c] == dictT[c]) {
formed++;
}

while (l <= r && formed == required) {
c = s1[l];

if (r - l + 1 < ans[0]) {
ans[0] = r - l + 1;
ans[1] = l;
ans[2] = r;
}

windowCounts[c]--;
if (dictT.ContainsKey(c) && windowCounts[c] < dictT[c]) {
formed--;
}

l++;
}

r++;
}

return ans[0] == int.MaxValue ? "" : s1.Substring(ans[1], ans[0]);
}
}


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

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

Пример:
Input: s = "bcabc"
Output: "abc"


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

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

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

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

😎 Решение:
public class Solution {
public string RemoveDuplicateLetters(string s) {
var stack = new Stack<char>();
var seen = new HashSet<char>();
var lastOccurrence = new Dictionary<char, int>();
for (int i = 0; i < s.Length; i++) {
lastOccurrence[s[i]] = i;
}

for (int i = 0; i < s.Length; i++) {
char c = s[i];
if (!seen.Contains(c)) {
while (stack.Count > 0 && c < stack.Peek() && i < lastOccurrence[stack.Peek()]) {
seen.Remove(stack.Pop());
}
seen.Add(c);
stack.Push(c);
}
}
return new string(stack.Reverse().ToArray());
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 395. Longest Substring with At Least K Repeating Characters
Сложность: medium

Дана строка s и целое число k, верните длину самой длинной подстроки строки s, такая что частота каждого символа в этой подстроке больше или равна k.

Если такой подстроки не существует, верните 0.

Пример:
Input: s = "aaabb", k = 3
Output: 3
Explanation: The longest substring is "aaa", as 'a' is repeated 3 times.


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

1⃣Генерируйте подстроки из строки s, начиная с индекса start и заканчивая индексом end. Используйте массив countMap для хранения частоты каждого символа в подстроке.

2⃣Метод isValid использует countMap для проверки, что каждый символ в подстроке встречается как минимум k раз. Если условие выполняется, текущая подстрока считается допустимой.

3⃣Отслеживайте максимальную длину допустимой подстроки, обновляя её, когда найдена более длинная подстрока, удовлетворяющая условиям. В конце возвращайте длину самой длинной подстроки.

😎 Решение:
public class Solution {
public int LongestSubstring(string s, int k) {
if (s.Length == 0 || k > s.Length) {
return 0;
}
int[] countMap = new int[26];
int n = s.Length;
int result = 0;

for (int start = 0; start < n; start++) {
Array.Fill(countMap, 0);
for (int end = start; end < n; end++) {
countMap[s[end] - 'a']++;
if (IsValid(countMap, k)) {
result = Math.Max(result, end - start + 1);
}
}
}
return result;
}

private bool IsValid(int[] countMap, int k) {
int countLetters = 0, countAtLeastK = 0;
for (int i = 0; i < 26; i++) {
if (countMap[i] > 0) countLetters++;
if (countMap[i] >= k) countAtLeastK++;
}
return countLetters == countAtLeastK;
}
}


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

Дана строка s, переставьте символы строки s так, чтобы любые два соседних символа не были одинаковыми.

Верните любую возможную перестановку строки s или верните "", если это невозможно.

Пример:
Input: s = "aab"
Output: "aba"


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

1⃣Инициализируйте пустой список ans для хранения переставленных символов. Создайте приоритетную очередь pq, используя структуру данных кучи. Каждый элемент в pq — это кортеж, содержащий количество символов и сам символ. Приоритетная очередь упорядочена так, что элементы с большим количеством имеют более высокий приоритет.

2⃣Извлеките элемент с наивысшим приоритетом из pq. Присвойте его количество и символ переменным count_first и char_first соответственно. Если ans пуст или текущий символ char_first отличается от последнего символа в ans, добавьте char_first в ans. Если количество char_first не равно нулю, уменьшите его на один. Если обновленное количество больше нуля, поместите его обратно в pq. Перейдите к следующей итерации.

3⃣В противном случае, если char_first совпадает с последним символом в ans, нужно выбрать другой символ. Если pq пуста, верните пустую строку, так как переставить символы невозможно. Извлеките следующий элемент из pq, присвоив его количество и символ переменным count_second и char_second соответственно. Добавьте char_second в ans. Если количество char_second не равно нулю, уменьшите его на один. Если обновленное количество больше нуля, поместите его обратно в pq. Наконец, поместите оригинальный char_first обратно в pq. Верните переставленные символы как строку, объединив элементы в ans.

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

public class Solution {
public string ReorganizeString(string s) {
int[] charCounts = new int[26];
foreach (char c in s) {
charCounts[c - 'a']++;
}

var pq = new PriorityQueue<int[], int>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
for (int i = 0; i < 26; i++) {
if (charCounts[i] > 0) {
pq.Enqueue(new int[] { charCounts[i], i + 'a' }, charCounts[i]);
}
}

var result = new List<char>();
while (pq.Count > 0) {
var first = pq.Dequeue();
if (result.Count == 0 || first[1] != result[^1]) {
result.Add((char)first[1]);
if (--first[0] > 0) {
pq.Enqueue(first, first[0]);
}
} else {
if (pq.Count == 0) {
return "";
}
var second = pq.Dequeue();
result.Add((char)second[1]);
if (--second[0] > 0) {
pq.Enqueue(second, second[0]);
}
pq.Enqueue(first, first[0]);
}
}

return new string(result.ToArray());
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: №19. Remove Nth Node From End of List
Сложность: medium

Учитывая заголовок связанного списка, удалите n-й узел с конца списка и верните его заголовок.

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


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

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

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

3⃣Обновить ссылку, исключив n-й узел с конца.

😎 Решение:
public class Solution {
public ListNode RemoveNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0, head);
ListNode first = dummy, second = dummy;

for (int i = 0; i <= n; i++) {
first = first.next;
}

while (first != null) {
first = first.next;
second = second.next;
}

second.next = second.next.next;
return dummy.next;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 689. Maximum Sum of 3 Non-Overlapping Subarrays
Сложность: hard

Дан целочисленный массив nums и целое число k. Найдите три непересекающихся подмассива длины k с максимальной суммой и верните их.

Верните результат в виде списка индексов, представляющих начальную позицию каждого интервала (нумерация с 0). Если существует несколько ответов, верните лексикографически наименьший.

Пример:
Input: nums = [1,2,1,2,6,7,5,1], k = 2
Output: [0,3,5]
Explanation: Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically larger.


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

1⃣Предположим, что фиксирован j. Нам нужно узнать на интервалах i∈[0,j−k] и l∈[j+k,len(W)−1], где наибольшее значение W[i] (и соответственно W[l]) встречается первым (то есть, с наименьшим индексом).

2⃣Мы можем решить эту задачу с помощью динамического программирования. Например, если мы знаем, что i - это место, где наибольшее значение W[i] встречается первым на [0,5], то на [0,6] первое появление наибольшего W[i] должно быть либо i, либо 6. Если, скажем, 6 лучше, тогда мы устанавливаем best = 6. В конце left[z] будет первым вхождением наибольшего значения W[i] на интервале i∈[0,z], а right[z] будет таким же, но на интервале i∈[z,len(W)−1].

3⃣Это означает, что для некоторого выбора j, кандидат на ответ должен быть (left[j - k], j, right[j + k]). Мы выбираем кандидата, который дает максимальное значение W[i] + W[j] + W[l].

😎 Решение:
public class Solution {
public int[] MaxSumOfThreeSubarrays(int[] nums, int k) {
int[] W = new int[nums.Length - k + 1];
int currSum = 0;
for (int i = 0; i < nums.Length; i++) {
currSum += nums[i];
if (i >= k) {
currSum -= nums[i - k];
}
if (i >= k - 1) {
W[i - k + 1] = currSum;
}
}

int[] left = new int[W.Length];
int best = 0;
for (int i = 0; i < W.Length; i++) {
if (W[i] > W[best]) best = i;
left[i] = best;
}

int[] right = new int[W.Length];
best = W.Length - 1;
for (int i = W.Length - 1; i >= 0; i--) {
if (W[i] >= W[best]) best = i;
right[i] = best;
}

int[] ans = new int[] {-1, -1, -1};
for (int j = k; j < W.Length - k; j++) {
int i = left[j - k], l = right[j + k];
if (ans[0] == -1 || W[i] + W[j] + W[l] > W[ans[0]] + W[ans[1]] + W[ans[2]]) {
ans[0] = i;
ans[1] = j;
ans[2] = l;
}
}
return ans;
}
}


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

Дан массив точек в плоскости X-Y points, где points[i] = [xi, yi]. Верните минимальную площадь прямоугольника, образованного из этих точек, со сторонами, параллельными осям X и Y. Если такого прямоугольника не существует, верните 0.

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


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

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

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

3⃣Если минимальная площадь остается бесконечной, вернуть 0. Иначе вернуть минимальную площадь.

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

public class Solution {
public int MinAreaRect(int[][] points) {
var pointSet = new HashSet<string>();
foreach (var point in points) {
pointSet.Add($"{point[0]},{point[1]}");
}

int minArea = int.MaxValue;
for (int i = 0; i < points.Length; i++) {
for (int j = i + 1; j < points.Length; j++) {
int x1 = points[i][0], y1 = points[i][1];
int x2 = points[j][0], y2 = points[j][1];
if (x1 != x2 && y1 != y2 && pointSet.Contains($"{x1},{y2}") && pointSet.Contains($"{x2},{y1}")) {
minArea = Math.Min(minArea, Math.Abs(x2 - x1) * Math.Abs(y2 - y1));
}
}
}

return minArea == int.MaxValue ? 0 : minArea;
}
}


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

Дана матрица размером m x n. Вернуть true, если матрица является Тёплицевой. В противном случае вернуть false.

Матрица является Тёплицевой, если все диагонали, идущие от верхнего левого к нижнему правому углу, содержат одинаковые элементы.

Пример:
Input: matrix = [[1,2,3,4],[5,1,2,3],[9,5,1,2]]
Output: true
Explanation:
In the above grid, the diagonals are:
"[9]", "[5, 5]", "[1, 1, 1]", "[2, 2, 2]", "[3, 3]", "[4]".
In each diagonal all elements are the same, so the answer is True.


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

1⃣Что отличает две координаты (r1, c1) и (r2, c2) на одной диагонали? Оказывается, две координаты находятся на одной диагонали тогда и только тогда, когда r1 - c1 == r2 - c2.м

2⃣Это приводит к следующей идее: запоминайте значение этой диагонали как groups[r - c]. Если обнаружено несоответствие, то матрица не является Тёплицевой; в противном случае, она является таковой.

3⃣Таким образом, для каждой ячейки матрицы сохраняйте значение диагонали в словаре groups с ключом r - c. Проходите по всем ячейкам матрицы и проверяйте, совпадает ли текущее значение с сохранённым в groups. Если где-то обнаруживается несоответствие, верните false. Если все элементы соответствуют, верните true.

😎 Решение:
public class Solution {
public bool IsToeplitzMatrix(int[][] matrix) {
Dictionary<int, int> groups = new Dictionary<int, int>();
for (int r = 0; r < matrix.Length; ++r) {
for (int c = 0; c < matrix[0].Length; ++c) {
if (!groups.ContainsKey(r - c))
groups[r - c] = matrix[r][c];
else if (groups[r - c] != matrix[r][c])
return false;
}
}
return true;
}
}


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

Дан массив целых чисел arr. Вы можете выбрать набор чисел и удалить все вхождения этих чисел из массива.

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

Пример:
Input: arr = [3,3,3,3,5,5,5,2,2,7]
Output: 2
Explanation: Choosing {3,7} will make the new array [5,5,5,2,2] which has size 5 (i.e equal to half of the size of the old array).
Possible sets of size 2 are {3,5},{3,2},{5,2}.
Choosing set {2,7} is not possible as it will make the new array [3,3,3,3,5,5,5] which has a size greater than half of the size of the old array.


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

1⃣Отсортировать массив и создать список подсчета количества вхождений каждого числа.

2⃣Отсортировать список подсчета в порядке убывания.

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

😎 Решение:
public class Solution {
public int MinSetSize(int[] arr) {
Array.Sort(arr);

List<int> counts = new List<int>();
int currentRun = 1;
for (int i = 1; i < arr.Length; i++) {
if (arr[i] == arr[i - 1]) {
currentRun += 1;
continue;
}
counts.Add(currentRun);
currentRun = 1;
}
counts.Add(currentRun);

counts.Sort((a, b) => b.CompareTo(a));

int numbersRemovedFromArr = 0;
int setSize = 0;
foreach (int count in counts) {
numbersRemovedFromArr += count;
setSize += 1;
if (numbersRemovedFromArr >= arr.Length / 2) {
break;
}
}

return setSize;
}
}


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

Вам дана сетка n x n, представляющая поле вишен. Каждая клетка - одно из трех возможных целых чисел. 0 означает, что клетка пуста, и вы можете пройти через нее, 1 означает, что клетка содержит вишню, которую вы можете сорвать и пройти через нее, или -1 означает, что клетка содержит шип, который преграждает вам путь. Верните максимальное количество вишен, которое вы можете собрать, следуя следующим правилам: Начиная с позиции (0, 0) и достигая (n - 1, n - 1) путем перемещения вправо или вниз через допустимые клетки пути (клетки со значением 0 или 1).
После достижения (n - 1, n - 1) вернитесь в (0, 0), двигаясь влево или вверх по клеткам с действительными путями. Проходя через клетку пути, содержащую вишню, вы поднимаете ее, и клетка становится пустой клеткой 0. Если между (0, 0) и (n - 1, n - 1) нет действительного пути, то вишни собрать нельзя.

Пример:
Input: grid = [[0,1,-1],[1,0,-1],[1,1,1]]
Output: 5


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

1⃣Используйте динамическое программирование для подсчета максимального количества вишен, которые можно собрать при движении от (0, 0) до (n - 1, n - 1).

2⃣Примените еще один проход с использованием динамического программирования для движения обратно от (n - 1, n - 1) до (0, 0), чтобы учитывать вишни, собранные на обратном пути.

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

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

public class Solution {
public int CherryPickup(int[][] grid) {
int n = grid.Length;
int[][][] dp = new int[n][][];
for (int i = 0; i < n; i++) {
dp[i] = new int[n][];
for (int j = 0; j < n; j++) {
dp[i][j] = new int[2 * n - 1];
Array.Fill(dp[i][j], int.MinValue);
}
}
dp[0][0][0] = grid[0][0];

for (int k = 1; k < 2 * n - 1; k++) {
for (int i1 = Math.Max(0, k - n + 1); i1 <= Math.Min(n - 1, k); i1++) {
for (int i2 = Math.Max(0, k - n + 1); i2 <= Math.Min(n - 1, k); i2++) {
int j1 = k - i1, j2 = k - i2;
if (j1 < n && j2 < n && grid[i1][j1] != -1 && grid[i2][j2] != -1) {
int maxCherries = int.MinValue;
if (i1 > 0 && i2 > 0) maxCherries = Math.Max(maxCherries, dp[i1 - 1][i2 - 1][k - 1]);
if (i1 > 0) maxCherries = Math.Max(maxCherries, dp[i1 - 1][i2][k - 1]);
if (i2 > 0) maxCherries = Math.Max(maxCherries, dp[i1][i2 - 1][k - 1]);
maxCherries = Math.Max(maxCherries, dp[i1][i2][k - 1]);
if (maxCherries != int.MinValue) {
dp[i1][i2][k] = maxCherries + grid[i1][j1];
if (i1 != i2) dp[i1][i2][k] += grid[i2][j2];
}
}
}
}
}

return Math.Max(0, dp[n - 1][n - 1][2 * n - 1]);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 201. Bitwise AND of Numbers Range
Сложность: medium

Даны два целых числа left и right, которые представляют диапазон [left, right], верните побитовое И всех чисел в этом диапазоне включительно.

Пример:
Input: left = 5, right = 7
Output: 4


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

1⃣Сдвигать left и right вправо, пока они не станут равными.

2⃣Подсчитать количество сдвигов.

3⃣Сдвинуть left влево на количество сдвигов и вернуть результат.

😎 Решение:
public class Solution {
public int RangeBitwiseAnd(int m, int n) {
int shift = 0;
while (m < n) {
m >>= 1;
n >>= 1;
shift++;
}
return m << shift;
}
}


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

Учитывая корень бинарного дерева, вернуть длину диаметра дерева.

Диаметр бинарного дерева — это длина самого длинного пути между любыми двумя узлами в дереве. Этот путь может проходить или не проходить через корень.

Длина пути между двумя узлами представлена числом ребер между ними.

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


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

1⃣Инициализируйте целочисленную переменную diameter для отслеживания самого длинного пути, найденного с помощью DFS.

2⃣Реализуйте рекурсивную функцию longestPath, которая принимает TreeNode в качестве входных данных и рекурсивно исследует дерево: Если узел равен None, вернуть 0. Рекурсивно исследовать левые и правые дочерние узлы, возвращая длины путей leftPath и rightPath. Если сумма leftPath и rightPath больше текущего diameter, обновить diameter. Вернуть большее из leftPath и rightPath плюс 1.

3⃣Вызвать longestPath с root.

😎 Решение:
public class Solution {
private int diameter;

public int DiameterOfBinaryTree(TreeNode root) {
diameter = 0;
LongestPath(root);
return diameter;
}

private int LongestPath(TreeNode node) {
if (node == null) return 0;

int leftPath = LongestPath(node.left);
int rightPath = LongestPath(node.right);

diameter = Math.Max(diameter, leftPath + rightPath);

return Math.Max(leftPath, rightPath) + 1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1509. Minimum Difference Between Largest and Smallest Value in Three Moves
Сложность: medium

Вам дан массив целых чисел nums.

За один ход вы можете выбрать один элемент массива nums и изменить его на любое значение.

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

Пример:
Input: nums = [5,3,2,4]
Output: 0
Explanation: We can make at most 3 moves.
In the first move, change 2 to 3. nums becomes [5,3,3,4].
In the second move, change 4 to 3. nums becomes [5,3,3,3].
In the third move, change 5 to 3. nums becomes [3,3,3,3].
After performing 3 moves, the difference between the minimum and maximum is 3 - 3 = 0.


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

1⃣Инициализация: определите размер массива nums, если размер меньше или равен 4, верните 0. Отсортируйте массив nums и инициализируйте переменную minDiff очень большим числом.

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

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

😎 Решение:
public class Solution {
public int MinDifference(int[] nums) {
int numsSize = nums.Length;

if (numsSize <= 4) return 0;

Array.Sort(nums);

int minDiff = int.MaxValue;

for (int left = 0, right = numsSize - 4; left < 4; left++, right++) {
minDiff = Math.Min(minDiff, nums[right] - nums[left]);
}

return minDiff;
}
}


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

Дано корневое дерево. Разделите бинарное дерево на два поддерева, удалив одно ребро так, чтобы произведение сумм поддеревьев было максимальным.

Верните максимальное произведение сумм двух поддеревьев. Поскольку ответ может быть слишком большим, верните его по модулю 10^9 + 7.

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

Пример:
Input: root = [1,2,3,4,5,6]
Output: 110
Explanation: Remove the red edge and get 2 binary trees with sum 11 and 10. Their product is 110 (11*10)


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

1⃣Рассчитать сумму значений всех узлов дерева и сохранить суммы всех поддеревьев в списке.

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

3⃣Найти максимальное произведение среди всех вычисленных и вернуть его значение по модулю 10^9 + 7.

😎 Решение:
public class Solution {
private List<int> allSums = new List<int>();

public int MaxProduct(TreeNode root) {
long totalSum = TreeSum(root);
long best = 0;
foreach (long sum in allSums) {
best = Math.Max(best, sum * (totalSum - sum));
}
return (int)(best % 1000000007);
}

private int TreeSum(TreeNode subroot) {
if (subroot == null) return 0;
int leftSum = TreeSum(subroot.left);
int rightSum = TreeSum(subroot.right);
int totalSum = leftSum + rightSum + subroot.val;
allSums.Add(totalSum);
return totalSum;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
🎉 easyoffer 2.0 — релиз уже в этом месяце!

Вас ждут новые фичи, о которых мы ранее даже не упоминали. Они сделают путь к офферам ещё быстрее и эффективнее. Расскажу о них чуть позже 👀

В честь запуска мы готовим ограниченную акцию:

Первые 500 покупателей получат:
🚀 PRO тариф на 1 год с 50% скидкой

Что нужно сделать:

🔔 Подпишитесь на этот Telegram-канал, чтобы первыми узнать о старте релиза. Сообщение появится в нем раньше, чем где-либо еще — вы успеете попасть в число первых 500 и получить максимальную выгоду. 🎁 А еще только для подписчиков канала ценный бонус в подарок к PRO тарифу.

📅 Официальный запуск — уже совсем скоро.
Следите за новостями и не пропустите старт!
Задача: 1017. Convert to Base -2
Сложность: medium

Если задано целое число n, верните двоичную строку, представляющую его в базе -2. Обратите внимание, что возвращаемая строка не должна содержать ведущих нулей, за исключением случаев, когда строка равна "0".

Пример:
Input: n = 2
Output: "110"


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

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

2⃣Вычисление цифр:
В цикле, пока число не равно 0, вычисляйте остаток от деления числа на -2.
Если остаток отрицательный, корректируйте его, добавляя 2, и увеличивайте число на 1.
Добавляйте остаток в начало строки.

3⃣Возврат результата:
Верните строку, представляющую число в базе -2. Если строка пустая, верните "0".

😎 Решение:
public class Solution {
public string BaseNeg2(int n) {
if (n == 0) return "0";
string res = "";
while (n != 0) {
int remainder = n % -2;
n /= -2;
if (remainder < 0) {
remainder += 2;
n += 1;
}
res = remainder.ToString() + res;
}
return res;
}
}


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

Дана строка s. Необходимо изменить порядок символов в каждом слове в предложении, сохранив при этом пробелы и начальный порядок слов.

Пример:
Input: s = "Let's take LeetCode contest"
Output: "s'teL ekat edoCteeL tsetnoc"


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

1⃣Создайте переменную lastSpaceIndex и установите её значение в -1. Пройдите по каждому символу строки s от 0-го до n-го индекса, используя указатель strIndex.

2⃣Когда strIndex указывает на пробел, определите начало (startIndex = lastSpaceIndex + 1) и конец (endIndex = strIndex - 1) текущего слова. Используя два указателя, измените порядок символов в текущем слове.

3⃣Обновите lastSpaceIndex значением strIndex. После окончания цикла измените порядок символов в последнем слове (от lastSpaceIndex + 1 до конца строки).

😎 Решение:
public class Solution {
public string ReverseWords(string s) {
char[] chars = s.ToCharArray();
int lastSpaceIndex = -1;
int len = chars.Length;

for (int strIndex = 0; strIndex <= len; strIndex++) {
if (strIndex == len || chars[strIndex] == ' ') {
int startIndex = lastSpaceIndex + 1;
int endIndex = strIndex - 1;
while (startIndex < endIndex) {
char temp = chars[startIndex];
chars[startIndex] = chars[endIndex];
chars[endIndex] = temp;
startIndex++;
endIndex--;
}
lastSpaceIndex = strIndex;
}
}

return new string(chars);
}
}


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