TGViewer
Channel Public Channel
C# | LeetCode

C# | LeetCode

@easy_c_sharp_task

Сайт: https://easyoffer.ru/
Все каналы: t.me/+xGeAw6ckJ4liYzQy

Контакт для рекламы: @sendme_ads
Subscribers
3.18K
Photos
200
Videos
0
Links
1.4K

Showing posts older than #1679 · Back to latest

Older Posts 20 shown
Post #1678 257
Задача: 951. Flip Equivalent Binary Trees
Сложность: medium

Для бинарного дерева T мы можем определить операцию переворота следующим образом: выбираем любой узел и меняем местами левое и правое дочерние поддеревья. Бинарное дерево X эквивалентно бинарному дереву Y тогда и только тогда, когда мы можем сделать X равным Y после некоторого количества операций переворота. Учитывая корни двух бинарных деревьев root1 и root2, верните true, если эти два дерева эквивалентны перевороту, или false в противном случае.

Пример:
Input: root1 = [1,2,3,4,5,6,null,null,null,7,8], root2 = [1,3,2,null,6,4,5,null,null,null,null,8,7]
Output: true


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

1⃣Если оба дерева пусты, они эквивалентны, вернуть true. Если одно дерево пустое, а другое нет, они не эквивалентны, вернуть false.

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

3⃣Вернуть true, если выполняется хотя бы одно из этих условий.

😎 Решение:
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 bool FlipEquiv(TreeNode root1, TreeNode root2) {
if (root1 == null && root2 == null) return true;
if (root1 == null || root2 == null) return false;
if (root1.val != root2.val) return false;

return (FlipEquiv(root1.left, root2.left) && FlipEquiv(root1.right, root2.right)) ||
(FlipEquiv(root1.left, root2.right) && FlipEquiv(root1.right, root2.left));
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1677 276
Задача: 127. Word Ladder
Сложность: hard

Секвенция трансформации от слова beginWord к слову endWord с использованием словаря wordList представляет собой последовательность слов beginWord -> s1 -> s2 -> ... -> sk, при которой:

Каждая пара соседних слов отличается ровно одной буквой.
Каждый элемент si для 1 <= i <= k присутствует в wordList. Отметим, что beginWord не обязан быть в wordList.
sk равно endWord.
Для двух слов, beginWord и endWord, и словаря wordList, верните количество слов в кратчайшей секвенции трансформации от beginWord к endWord, или 0, если такая секвенция не существует.

Пример:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: 5
Explanation: One shortest transformation sequence is "hit" -> "hot" -> "dot" -> "dog" -> cog", which is 5 words long.


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

1⃣Препроцессинг списка слов: Осуществите препроцессинг заданного списка слов (wordList), чтобы найти все возможные промежуточные состояния слов. Сохраните эти состояния в словаре, где ключом будет промежуточное слово, а значением — список слов, имеющих то же промежуточное состояние.

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

3⃣Поиск кратчайшего пути через BFS (обход в ширину): Пока в очереди есть элементы, получите первый элемент очереди. Для каждого слова определите все промежуточные преобразования и проверьте, не являются ли эти преобразования также преобразованиями других слов из списка. Для каждого найденного слова, которое имеет общее промежуточное состояние с текущим словом, добавьте в очередь пару (слово, уровень + 1), где уровень — это уровень текущего слова. Если вы достигли искомого слова, его уровень покажет длину кратчайшей последовательности преобразования.

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

public class Solution {
public int LadderLength(string beginWord, string endWord, IList<string> wordList) {
int L = beginWord.Length;
Dictionary<string, List<string>> allComboDict = new Dictionary<string, List<string>>();
foreach (string word in wordList) {
for (int i = 0; i < L; i++) {
string newWord = word.Substring(0, i) + '*' + word.Substring(i + 1, L - i - 1);
if (!allComboDict.ContainsKey(newWord))
allComboDict[newWord] = new List<string>();
allComboDict[newWord].Add(word);
}
}

Queue<Tuple<string, int>> Q = new Queue<Tuple<string, int>>();
Q.Enqueue(new Tuple<string, int>(beginWord, 1));
Dictionary<string, bool> visited = new Dictionary<string, bool>();
visited[beginWord] = true;
while (Q.Any()) {
var node = Q.Dequeue();
string word = node.Item1;
int level = node.Item2;
for (int i = 0; i < L; i++) {
string newWord = word.Substring(0, i) + '*' + word.Substring(i + 1, L - i - 1);
foreach (string adjacentWord in allComboDict.GetValueOrDefault(newWord, new List<string>())) {
if (adjacentWord.Equals(endWord))
return level + 1;
if (!visited.ContainsKey(adjacentWord)) {
visited[adjacentWord] = true;
Q.Enqueue(new Tuple<string, int>(adjacentWord, level + 1));
}
}
}
}

return 0;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1676 276
Задача: 726. Number of Atoms
Сложность: hard

Если задана строковая формула, представляющая химическую формулу, верните количество атомов. Атомный элемент всегда начинается с прописного символа, затем ноль или более строчных букв, представляющих его название. Если количество больше 1, за ним может следовать одна или более цифр, представляющих количество элементов. Например, "H2O" и "H2O2" возможны, а "H1O2" невозможен. Две формулы объединяются вместе, чтобы получить другую формулу. Например, "H2O2He3Mg4" также является формулой.
Формула, заключенная в круглые скобки, и счет (по желанию) также являются формулами. Например, "(H2O2)" и "(H2O2)3" являются формулами.
Возвращает количество всех элементов в виде строки в следующем виде: первое имя (в отсортированном порядке), затем его количество (если это количество больше 1), затем второе имя (в отсортированном порядке), затем его количество (если это количество больше 1) и т. д. Тестовые примеры генерируются таким образом, чтобы все значения в выводе помещались в 32-битное целое число.

Пример:
Input: formula = "H2O"
Output: "H2O"


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

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

2⃣Пройдите по строке формулы, анализируя каждый символ: Если символ - это открывающая скобка '(', создайте новый словарь для хранения атомов внутри скобок. Если символ - это закрывающая скобка ')', извлеките словарь из стека и умножьте количества атомов на последующее число, если оно присутствует. Если символ - это атом (начинается с заглавной буквы), извлеките имя атома и его количество, и добавьте его в текущий словарь.

3⃣После завершения обработки строки, объедините все словари из стека и отсортируйте результат.

😎 Решение:
public class Solution {
public string CountOfAtoms(string formula) {
var stack = new Stack<Dictionary<string, int>>();
stack.Push(new Dictionary<string, int>());
int n = formula.Length;
int i = 0;

while (i < n) {
if (formula[i] == '(') {
stack.Push(new Dictionary<string, int>());
i++;
} else if (formula[i] == ')') {
var top = stack.Pop();
i++;
int start = i;
while (i < n && Char.IsDigit(formula[i])) {
i++;
}
int multiplicity = i > start ? int.Parse(formula.Substring(start, i - start)) : 1;
foreach (var name in top.Keys) {
int count = top[name];
if (stack.Peek().ContainsKey(name)) {
stack.Peek()[name] += count * multiplicity;
} else {
stack.Peek()[name] = count * multiplicity;
}
}
} else {
int start = i;
i++;
while (i < n && Char.IsLower(formula[i])) {
i++;
}
string name = formula.Substring(start, i - start);
start = i;
while (i < n && Char.IsDigit(formula[i])) {
i++;
}
int multiplicity = i > start ? int.Parse(formula.Substring(start, i - start)) : 1;
if (stack.Peek().ContainsKey(name)) {
stack.Peek()[name] += multiplicity;
} else {
stack.Peek()[name] = multiplicity;
}
}
}

var countMap = stack.Pop();
var sb = new StringBuilder();
foreach (var name in countMap.Keys.OrderBy(x => x)) {
sb.Append(name);
int count = countMap[name];
if (count > 1) {
sb.Append(count);
}
}
return sb.ToString();
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1675 310
Задача: 1672. Richest Customer Wealth
Сложность: easy

Вам дан целочисленный массив размером m x n под названием accounts, где accounts[i][j] — это сумма денег, которую i-й клиент имеет в j-м банке. Верните богатство самого богатого клиента.

Богатство клиента — это сумма денег, которую он имеет во всех своих банковских счетах. Самый богатый клиент — это клиент, который имеет максимальное богатство.

Пример:
Input: accounts = [[1,2,3],[3,2,1]]
Output: 6
Explanation:
1st customer has wealth = 1 + 2 + 3 = 6
2nd customer has wealth = 3 + 2 + 1 = 6
Both customers are considered the richest with a wealth of 6 each, so return 6.


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

1⃣Пройдите по всем клиентам в массиве accounts.

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

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

😎 Решение:
public class Solution {
public int MaximumWealth(int[][] accounts) {
int maxWealthSoFar = 0;

foreach (var account in accounts) {
int currCustomerWealth = account.Sum();
maxWealthSoFar = Math.Max(maxWealthSoFar, currCustomerWealth);
}

return maxWealthSoFar;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1674 280
Задача: 1238. Circular Permutation in Binary Representation
Сложность: medium

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

Пример:
Input: arr = ["un","iq","ue"]
Output: 4


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

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

2⃣Проверка уникальности символов:
Для проверки уникальности символов используем множество (set). Если все символы строки уникальны и не пересекаются с символами текущей комбинации, мы можем добавить строку.

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

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

public class Solution {
public int MaxLength(IList<string> arr) {
return Backtrack(arr, 0, "");
}

private bool IsUnique(string s) {
HashSet<char> charSet = new HashSet<char>(s);
return charSet.Count == s.Length;
}

private int Backtrack(IList<string> arr, int index, string current) {
if (!IsUnique(current)) return 0;
int maxLength = current.Length;
for (int i = index; i < arr.Count; i++) {
maxLength = Math.Max(maxLength, Backtrack(arr, i + 1, current + arr[i]));
}
return maxLength;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1673 263
Задача: 997. Find the Town Judge
Сложность: easy

В городе есть n человек, помеченных от 1 до n. Ходят слухи, что один из этих людей тайно является городским судьей. Если городской судья существует, то: городской судья никому не доверяет. Все (кроме городского судьи) доверяют городскому судье. Существует ровно один человек, удовлетворяющий свойствам 1 и 2. Вам дан массив trust, где trust[i] = [ai, bi], представляющий, что человек, помеченный ai, доверяет человеку, помеченному bi. Если в массиве trust не существует доверительных отношений, то таких отношений не существует. Верните метку городского судьи, если городской судья существует и может быть идентифицирован, или верните -1 в противном случае.

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


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

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

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

3⃣Проверка условий судьи:
Пройдитесь по массиву людей и найдите того, кто никому не доверяет (количество доверий равно 0) и кому доверяют все остальные (количество доверенных людей равно n-1). Верните метку этого человека. Если такого человека нет, верните -1.

😎 Решение:
public class Solution {
public int FindJudge(int n, int[][] trust) {
if (trust.Length == 0 && n == 1) {
return 1;
}

int[] trustCount = new int[n + 1];
int[] trustedBy = new int[n + 1];

foreach (var t in trust) {
trustCount[t[0]]++;
trustedBy[t[1]]++;
}

for (int i = 1; i <= n; i++) {
if (trustCount[i] == 0 && trustedBy[i] == n - 1) {
return i;
}
}

return -1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1672 323
Задача: 989. Add to Array-Form of Integer
Сложность: easy

Массивная форма целого числа num - это массив, представляющий его цифры в порядке слева направо.

Например, для num = 1321, массивная форма - это [1, 3, 2, 1].
Дано num в массивной форме целого числа и целое число k, верните массивную форму числа num + k.

Пример:
Input: num = [1,2,0,0], k = 34
Output: [1,2,3,4]
Explanation: 1200 + 34 = 1234


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

1⃣Инициализация переменных:
Преобразуйте число k в массив его цифр и переверните оба массива (массив num и массив цифр k).
Завести переменную carry для хранения переноса и инициализировать ее нулем.
Создать пустой массив result для хранения результата.

2⃣Сложение массивов:
Пройдите по элементам массивов num и цифр k, начиная с их конца, сложите соответствующие цифры вместе с переносом (carry).
Если сумма больше 9, сохраните последнюю цифру в текущей позиции результата, а carry установите в 1.
Если сумма меньше 10, установите carry в 0.
Добавьте результат текущего сложения в массив result

3⃣Обработка оставшихся цифр и переноса:
Если один из массивов закончился раньше, продолжайте сложение оставшихся цифр другого массива с переносом.
Если после окончания всех сложений остается перенос (carry), добавьте его в начало массива result.
Переверните массив result обратно и верните его.

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

public class Solution {
public IList<int> AddToArrayForm(int[] num, int k) {
List<int> result = new List<int>();
int n = num.Length;

for (int i = n - 1; i >= 0; i--) {
k += num[i];
result.Add(k % 10);
k /= 10;
}
while (k > 0) {
result.Add(k % 10);
k /= 10;
}
result.Reverse();
return result;
}
}


Ставь 👍 и забирай 📚 Базу знаний
  • 🤔 1
Post #1671 272
Задача: 924. Minimize Malware Spread
Сложность: hard

Вам дана сеть из n узлов, представленная в виде графа с матрицей смежности n x n, где i-й узел непосредственно связан с j-м узлом, если graph[i][j] == 1. Некоторые узлы изначально заражены вредоносным ПО. Если два узла соединены напрямую и хотя бы один из них заражен вредоносным ПО, то оба узла будут заражены вредоносным ПО. Такое распространение вредоносного ПО будет продолжаться до тех пор, пока не останется ни одного узла, который можно было бы заразить таким образом. Предположим, что M(initial) - это конечное число узлов, зараженных вредоносным ПО, во всей сети после прекращения распространения вредоносного ПО. Мы удалим из initial ровно один узел. Верните тот узел, удаление которого минимизирует M(initial). Если можно удалить несколько узлов, чтобы минимизировать M(initial), верните такой узел с наименьшим индексом. Обратите внимание, что если узел был удален из начального списка зараженных узлов, он все равно может быть заражен позже из-за распространения вредоносного ПО.

Пример:
Input: arr = [1,1,2,2,3,3,4,4,5,5], target = 8
Output: 20


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

1⃣Определить количество зараженных узлов после распространения вредоносного ПО для исходного списка initial.

2⃣Для каждого узла в initial удалить его и вычислить количество зараженных узлов после распространения вредоносного ПО.

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

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

public class Solution {
public int MinMalwareSpread(int[][] graph, int[] initial) {
int n = graph.Length;
HashSet<int> initialSet = new HashSet<int>(initial);
Array.Sort(initial);
int minInfected = int.MaxValue;
int bestNode = initial[0];

foreach (int node in initial) {
HashSet<int> infected = new HashSet<int>(initialSet);
infected.Remove(node);
foreach (int i in initialSet) {
if (i != node) {
Dfs(graph, i, infected);
}
}
if (infected.Count < minInfected) {
minInfected = infected.Count;
bestNode = node;
}
}

return bestNode;
}

private void Dfs(int[][] graph, int node, HashSet<int> infected) {
for (int neighbor = 0; neighbor < graph.Length; neighbor++) {
if (graph[node][neighbor] == 1 && !infected.Contains(neighbor)) {
infected.Add(neighbor);
Dfs(graph, neighbor, infected);
}
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1670 264
Задача: 1382. Balance a Binary Search Tree
Сложность: medium

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

Бинарное дерево поиска считается сбалансированным, если глубина двух поддеревьев каждого узла никогда не отличается более чем на 1.

Пример:
Input: root = [1,null,2,null,3,null,4,null,null]
Output: [2,1,3,null,null,null,4]
Explanation: This is not the only correct answer, [3,1,4,null,2] is also correct.


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

1⃣Инициализация. Создайте пустой список inorder для хранения значений узлов после обхода в порядке возрастания.

2⃣Выполнение обхода в порядке возрастания. Обойдите бинарное дерево поиска (BST) и заполните список inorder значениями узлов в отсортированном порядке.

3⃣Перестроение сбалансированного BST. Определите рекурсивную функцию createBalancedBST, которая принимает список inorder, начальный индекс и конечный индекс в качестве параметров. Если начальный индекс больше конечного, верните null (или эквивалент). Вычислите средний индекс как середину текущего диапазона. Создайте новый узел дерева со значением в среднем индексе. Рекурсивно создайте левое поддерево, используя левую половину текущего диапазона. Рекурсивно создайте правое поддерево, используя правую половину текущего диапазона. Верните корень вновь построенного сбалансированного BST.

😎 Решение:
public class Solution {
public TreeNode BalanceBST(TreeNode root) {
if (root == null) return null;

TreeNode vineHead = new TreeNode(0);
vineHead.right = root;
TreeNode current = vineHead;

while (current.right != null) {
if (current.right.left != null) {
RightRotate(current, current.right);
} else {
current = current.right;
}
}

int nodeCount = 0;
current = vineHead.right;
while (current != null) {
nodeCount++;
current = current.right;
}

int m = (int)Math.Pow(2, Math.Floor(Math.Log(nodeCount + 1) / Math.Log(2))) - 1;
MakeRotations(vineHead, nodeCount - m);
while (m > 1) {
m /= 2;
MakeRotations(vineHead, m);
}

TreeNode balancedRoot = vineHead.right;
return balancedRoot;
}

private void RightRotate(TreeNode parent, TreeNode node) {
TreeNode tmp = node.left;
node.left = tmp.right;
tmp.right = node;
parent.right = tmp;
}

private void LeftRotate(TreeNode parent, TreeNode node) {
TreeNode tmp = node.right;
node.right = tmp.left;
tmp.left = node;
parent.right = tmp;
}

private void MakeRotations(TreeNode vineHead, int count) {
TreeNode current = vineHead;
for (int i = 0; i < count; i++) {
TreeNode tmp = current.right;
LeftRotate(current, tmp);
current = current.right;
}
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1669 263
Задача: 763. Partition Labels
Сложность: medium

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

Пример:
Input: s = "ababcbacadefegdehijhklij"
Output: [9,7,8]


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

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

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

3⃣Когда текущая позиция совпадает с максимальной позицией, завершите часть и начните новую.

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

public class Solution {
public IList<int> PartitionLabels(string s) {
int[] lastPos = new int[26];
for (int i = 0; i < s.Length; i++) {
lastPos[s[i] - 'a'] = i;
}

List<int> partitions = new List<int>();
int j = 0, anchor = 0;
for (int i = 0; i < s.Length; i++) {
j = Math.Max(j, lastPos[s[i] - 'a']);
if (i == j) {
partitions.Add(i - anchor + 1);
anchor = i + 1;
}
}
return partitions;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1668 229
Задача: 1125. Smallest Sufficient Team
Сложность: hard

В проекте у вас есть список необходимых навыков req_skills и список людей. i-й человек people[i] содержит список навыков, которыми обладает этот человек.

Рассмотрим достаточную команду: набор людей, такой что для каждого необходимого навыка из req_skills, есть по крайней мере один человек в команде, который обладает этим навыком. Мы можем представить эти команды индексами каждого человека.

Например, команда = [0, 1, 3] представляет людей с навыками people[0], people[1] и people[3].
Верните любую достаточную команду наименьшего возможного размера, представленную индексами каждого человека. Вы можете вернуть ответ в любом порядке.

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

Пример:
Input: req_skills = ["algorithms","math","java","reactjs","csharp","aws"],
people = [["algorithms","math","java"],["algorithms","math","reactjs"],
["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]]
Output: [1,2]


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

1⃣Инициализация и создание масок навыков:
Определите количество людей n и количество необходимых навыков m.
Создайте хэш-таблицу skillId, чтобы сопоставить каждому навыку уникальный индекс.
Создайте массив skillsMaskOfPerson, который будет содержать битовые маски навыков для каждого человека.

2⃣Динамическое программирование (DP):
Создайте массив dp размера 2^m и заполните его значениями (1 << n) - 1.
Установите dp[0] в 0 (базовый случай).
Для каждого skillsMask от 1 до 2^m - 1:
- для каждого человека i:
- вычислите smallerSkillsMask как skillsMask & ~skillsMaskOfPerson[i].
- если smallerSkillsMask отличается от skillsMask, обновите dp[skillsMask], если новая команда лучше (имеет меньше установленных битов).

3⃣Формирование ответа:
Извлеките ответ из dp и верните массив индексов людей, составляющих минимальную достаточную команду.

😎 Решение:
public class Solution {
public int[] SmallestSufficientTeam(string[] req_skills, IList<IList<string>> people) {
int n = people.Count, m = req_skills.Length;
var skillId = new Dictionary<string, int>();
for (int i = 0; i < m; i++) {
skillId[req_skills[i]] = i;
}
var skillsMaskOfPerson = new int[n];
for (int i = 0; i < n; i++) {
foreach (var skill in people[i]) {
if (skillId.ContainsKey(skill)) {
skillsMaskOfPerson[i] |= 1 << skillId[skill];
}
}
}
var dp = new long[1 << m];
Array.Fill(dp, (1L << n) - 1);
dp[0] = 0;
for (int skillsMask = 1; skillsMask < (1 << m); skillsMask++) {
for (int i = 0; i < n; i++) {
int smallerSkillsMask = skillsMask & ~skillsMaskOfPerson[i];
if (smallerSkillsMask != skillsMask) {
long peopleMask = dp[smallerSkillsMask] | (1L << i);
if (BitCount(peopleMask) < BitCount(dp[skillsMask])) {
dp[skillsMask] = peopleMask;
}
}
}
}
long answerMask = dp[(1 << m) - 1];
var ans = new List<int>();
for (int i = 0; i < n; i++) {
if (((answerMask >> i) & 1) == 1) {
ans.Add(i);
}
}
return ans.ToArray();
}

private int BitCount(long value) {
int count = 0;
while (value != 0) {
value &= (value - 1);
count++;
}
return count;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1667 270
Задача: 42. Trapping Rain Water
Сложность: hard

Дан массив height, где height[i] представляет высоту столбца. Нужно вычислить, сколько воды может удержаться после дождя.

Пример:
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]  
Output: 6


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

1⃣Создать массив left_max, где left_max[i] — максимальная высота слева до i.

2⃣Создать массив right_max, где right_max[i] — максимальная высота справа до i.

3⃣Для каждого i, вычислить возможный объем воды как min(left_max[i], right_max[i]) - height[i] и суммировать.

😎 Решение:
public class Solution {
public int Trap(int[] height) {
if (height.Length == 0) return 0;

int size = height.Length, ans = 0;
int[] left_max = new int[size];
int[] right_max = new int[size];

left_max[0] = height[0];
for (int i = 1; i < size; i++) {
left_max[i] = Math.Max(height[i], left_max[i - 1]);
}

right_max[size - 1] = height[size - 1];
for (int i = size - 2; i >= 0; i--) {
right_max[i] = Math.Max(height[i], right_max[i + 1]);
}

for (int i = 1; i < size - 1; i++) {
ans += Math.Min(left_max[i], right_max[i]) - height[i];
}

return ans;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1666 270
Задача: 815. Bus Routes
Сложность: hard

Дан массив routes, представляющий автобусные маршруты, где routes[i] - это автобусный маршрут, который i-й автобус повторяет бесконечно.

Например, если routes[0] = [1, 5, 7], это означает, что 0-й автобус путешествует в последовательности 1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ... бесконечно.
Вы начинаете на автобусной остановке source (вы изначально не находитесь в автобусе) и хотите добраться до автобусной остановки target. Перемещаться между автобусными остановками можно только на автобусах.

Верните наименьшее количество автобусов, которые вам нужно взять, чтобы доехать от source до target. Верните -1, если это невозможно.

Пример:
Input: routes = [[1,2,7],[3,6,7]], source = 1, target = 6
Output: 2
Explanation: The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.


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

1⃣Верните 0, если source и target совпадают. Инициализируйте пустую карту adjList, чтобы хранить ребра, где ключ - это автобусная остановка, а значение - список целых чисел, обозначающих индексы маршрутов, которые имеют эту остановку. Инициализируйте пустую очередь q и неупорядоченное множество vis, чтобы отслеживать посещенные маршруты. Вставьте начальные маршруты в очередь q и отметьте их посещенными в vis.

2⃣Итерация по очереди, пока она не пуста: извлеките маршрут из очереди, итерируйтесь по остановкам в маршруте. Если остановка равна target, верните busCount. В противном случае, итерируйтесь по маршрутам для этой остановки в карте adjList, добавьте непосещенные маршруты в очередь и отметьте их посещенными.

3⃣Верните -1 после завершения обхода в ширину (BFS).

😎 Решение:
public class Solution {
public int NumBusesToDestination(int[][] routes, int source, int target) {
if (source == target) return 0;

var adjList = new Dictionary<int, List<int>>();
for (int route = 0; route < routes.Length; route++) {
foreach (int stop in routes[route]) {
if (!adjList.ContainsKey(stop)) {
adjList[stop] = new List<int>();
}
adjList[stop].Add(route);
}
}

var q = new Queue<int>();
var vis = new HashSet<int>();
foreach (int route in adjList.GetValueOrDefault(source, new List<int>())) {
q.Enqueue(route);
vis.Add(route);
}

int busCount = 1;
while (q.Count > 0) {
int size = q.Count;
for (int i = 0; i < size; i++) {
int route = q.Dequeue();
foreach (int stop in routes[route]) {
if (stop == target) return busCount;
foreach (int nextRoute in adjList.GetValueOrDefault(stop, new List<int>())) {
if (!vis.Contains(nextRoute)) {
vis.Add(nextRoute);
q.Enqueue(nextRoute);
}
}
}
}
busCount++;
}
return -1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1665 335
Задача: 1276. Number of Burgers with No Waste of Ingredients
Сложность: medium

Даны два целых числа tomatoSlices и cheeseSlices. Ингредиенты разных бургеров таковы: Jumbo Burger: 4 ломтика помидора и 1 ломтик сыра. Small Burger: 2 ломтика помидора и 1 ломтик сыра. Верните [total_jumbo, total_small] так, чтобы количество оставшихся tomatoSlices было равно 0, а количество оставшихся cheeseSlices было равно 0. Если невозможно сделать так, чтобы оставшиеся tomatoSlices и cheeseSlices были равны 0, верните [].

Пример:
Input: tomatoSlices = 16, cheeseSlices = 7
Output: [1,6]


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

1⃣Проверьте, возможно ли решить задачу, убедившись, что tomatoSlices четно и находится в допустимых пределах.

2⃣Решите систему уравнений:
4J + 2S = tomatoSlices
J + S = cheeseSlices

3⃣Если решение существует, верните его, иначе верните пустой список.

😎 Решение:
public class Solution {
public IList<int> NumOfBurgers(int tomatoSlices, int cheeseSlices) {
if (tomatoSlices % 2 != 0 || tomatoSlices < 2 * cheeseSlices || tomatoSlices > 4 * cheeseSlices) {
return new List<int>();
}
int total_jumbo = (tomatoSlices - 2 * cheeseSlices) / 2;
int total_small = cheeseSlices - total_jumbo;
return new List<int> { total_jumbo, total_small };
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1663 337
Задача: 477. Total Hamming Distance
Сложность: medium

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

Дан целочисленный массив nums, верните сумму Хэмминговых расстояний между всеми парами чисел в nums.

Пример:
Input: nums = [4,14,2]
Output: 6
Explanation: In binary representation, the 4 is 0100, 14 is 1110, and 2 is 0010 (just
showing the four bits relevant in this case).
The answer will be:
HammingDistance(4, 14) + HammingDistance(4, 2) + HammingDistance(14, 2) = 2 + 2 + 2 = 6.


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

1⃣Для каждой уникальной пары элементов из массива вычисляем битовое XOR, чтобы найти позиции, где биты различаются. Бит, равный 1 в результате, указывает на различие.

2⃣Для каждой пары элементов используем XOR, чтобы получить битовую разницу, и подсчитываем количество битов, равных 1, чтобы определить Хэммингово расстояние между парой.

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

😎 Решение:
public class Solution {
public int TotalHammingDistance(int[] nums) {
int ans = 0;

if (nums.Length == 0) {
return ans;
}

for (int i = 0; i < nums.Length - 1; i++) {
for (int j = i + 1; j < nums.Length; j++) {
ans += CountBits(nums[i] ^ nums[j]);
}
}

return ans;
}

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


Ставь 👍 и забирай 📚 Базу знаний
Post #1662 298
Задача: 345. Reverse Vowels of a String
Сложность: easy

Дана строка s, переверните только все гласные в строке и верните её.

Гласные: 'a', 'e', 'i', 'o', 'u', а также их верхние регистры.

Пример:
Input: s = "hello"
Output: "holle"


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

1⃣Инициализация указателей и гласных:
Создайте набор гласных для быстрой проверки.
Установите два указателя: один на начало строки (left), другой на конец строки (right).

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

3⃣Завершение работы:
Когда указатели пересекутся, остановите процесс и верните строку.

😎 Решение:
public class Solution {
public string ReverseVowels(string s) {
HashSet<char> vowels = new HashSet<char>{'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'};
char[] chars = s.ToCharArray();
int left = 0, right = s.Length - 1;

while (left < right) {
if (!vowels.Contains(chars[left])) {
left++;
} else if (!vowels.Contains(chars[right])) {
right--;
} else {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
}

return new string(chars);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1661 273
Задача: 541. Reverse String II
Сложность: easy

Дана строка s и целое число k, переверните первые k символов для каждых 2k символов, начиная с начала строки.

Если осталось меньше k символов, переверните все. Если осталось меньше 2k, но больше или равно k символов, переверните первые k символов и оставьте остальные как есть.

Пример:
Input: s = "abcdefg", k = 2
Output: "bacdfeg"


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

1⃣Разворачиваем каждый блок из 2k символов непосредственно. Каждый блок начинается с кратного 2k: например, 0, 2k, 4k, 6k и так далее.

2⃣Будьте внимательны, если символов недостаточно, блок может не быть перевернут.

3⃣Для разворота блока символов с позиции i до j, меняем местами символы на позициях i++ и j--.

😎 Решение:
class Solution {
public string ReverseStr(string s, int k) {
char[] a = s.ToCharArray();
for (int start = 0; start < a.Length; start += 2 * k) {
int i = start, j = Math.Min(start + k - 1, a.Length - 1);
while (i < j) {
char tmp = a[i];
a[i++] = a[j];
a[j--] = tmp;
}
}
return new string(a);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1660 273
Задача: 1360. Number of Days Between Two Dates
Сложность: easy

Напишите программу для подсчета количества дней между двумя датами.

Даты даны в виде строк в формате YYYY-MM-DD, как показано в примерах.

Пример:
Input: date1 = "2019-06-29", date2 = "2019-06-30"
Output: 1


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

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

2⃣Вычисление разницы в днях:
Вычислите разницу между двумя объектами дат в днях.

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

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

public class Solution {
public int DaysBetweenDates(string date1, string date2) {
DateTime d1 = DateTime.Parse(date1);
DateTime d2 = DateTime.Parse(date2);
return Math.Abs((d2 - d1).Days);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1659 288
Задача: 724. Find Pivot Index
Сложность: easy

Если задан массив целых чисел nums, вычислите поворотный индекс этого массива. Поворотный индекс - это индекс, при котором сумма всех чисел строго слева от индекса равна сумме всех чисел строго справа от индекса. Если индекс находится на левом краю массива, то сумма слева равна 0, так как слева нет элементов. Это относится и к правому краю массива. Возвращается самый левый поворотный индекс. Если такого индекса не существует, возвращается -1.

Пример:
Input: nums = [1,7,3,6,5,6]
Output: 3


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

1⃣Вычислите сумму всех элементов массива.

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

3⃣Если текущий индекс удовлетворяет условию, верните его; если нет, продолжайте проверку. Если такой индекс не найден, верните -1.

😎 Решение:
public class Solution {
public int PivotIndex(int[] nums) {
int totalSum = 0;
foreach (int num in nums) {
totalSum += num;
}
int leftSum = 0;
for (int i = 0; i < nums.Length; i++) {
if (leftSum == totalSum - leftSum - nums[i]) {
return i;
}
leftSum += nums[i];
}
return -1;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Post #1658 264
Задача: 1048. Longest String Chain
Сложность: easy

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

Например, "abc" является предшественником "abac", а "cba" не является предшественником "bcad". Цепочка слов - это последовательность слов [word1, word2, ..., wordk] с k >= 1, где word1 является предшественником word2, word2 является предшественником word3 и так далее. Одиночное слово тривиально является цепочкой слов с k == 1. Верните длину самой длинной возможной цепочки слов со словами, выбранными из заданного списка слов.

Пример:
Input: words = ["a","b","ba","bca","bda","bdca"]
Output: 4


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

1⃣Отсортируй список слов по длине.

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

3⃣Верни максимальную длину среди всех цепочек.

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

public class Solution {
public int LongestStrChain(string[] words) {
Array.Sort(words, (a, b) => a.Length - b.Length);
var dp = new Dictionary<string, int>();
int longestChain = 1;

foreach (var word in words) {
dp[word] = 1;
for (int i = 0; i < word.Length; i++) {
string predecessor = word.Substring(0, i) + word.Substring(i + 1);
if (dp.ContainsKey(predecessor)) {
dp[word] = Math.Max(dp[word], dp[predecessor] + 1);
}
}
longestChain = Math.Max(longestChain, dp[word]);
}

return longestChain;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →