C/C++ | LeetCode
Ir al canal en Telegram
Cайт easyoffer.ru Реклама @easyoffer_adv ВП @easyoffer_vp Тесты t.me/+zYofcX2VLTM3MGMy Вопросы собесов t.me/+BTbqlW1VbIFmYmVi Вакансии t.me/+za2mJYs4riAzMzFi
Mostrar más3 254
Suscriptores
-224 horas
-57 días
-1030 días
Archivo de publicaciones
3 254
Онлайн-магистратура «DevOps-инженер облачных сервисов»
День открытых дверей
26 марта в 19:00 мск | Онлайн
Эксперты Яндекса и ИТМО расскажут об очной онлайн-магистратуре для карьеры в IT.
Всё о поступлении и обучении, выступления экспертов, ответы на вопросы.
Забронировать
#реклама 16+
practicum.yandex.ru
О рекламодателе
3 254
#medium
Задача: 753. Cracking the Safe
Имеется сейф, защищенный паролем. Пароль представляет собой последовательность из n цифр, каждая из которых может находиться в диапазоне [0, k - 1]. Сейф имеет особый способ проверки пароля. Например, правильный пароль - "345", а вы вводите "012345": после ввода 0 последние 3 цифры - "0", что неверно. После ввода 1 последние 3 цифры - "01", что неверно. После ввода 2 последние 3 цифры - "012", что неверно.
После ввода 3 последние 3 цифры - "123", что неверно. После ввода 4 последние 3 цифры - "234", что неверно. После ввода 5 последние 3 цифры - "345", что верно, и сейф разблокируется. Верните любую строку минимальной длины, которая разблокирует сейф на определенном этапе ввода.
Пример:
Input: n = 1, k = 2 Output: "10"👨💻 Алгоритм: 1⃣Создайте граф, где каждая вершина представляет собой строку длины n-1, а каждое ребро между двумя вершинами представляет собой добавление одной из цифр из диапазона [0, k-1]. 2⃣Используйте алгоритм Эйлерова пути или цикла для нахождения пути, который проходит через каждое ребро ровно один раз. 3⃣Составьте итоговую строку, которая включает начальную вершину и все добавленные цифры. 😎 Решение:
class Solution {
public:
string crackSafe(int n, int k) {
unordered_set<string> seen;
string result;
string startNode(n - 1, '0');
dfs(startNode, k, seen, result);
result += startNode;
return result;
}
private:
void dfs(const string& node, int k, unordered_set<string>& seen, string& result) {
for (int x = 0; x < k; ++x) {
string neighbor = node + to_string(x);
if (!seen.count(neighbor)) {
seen.insert(neighbor);
dfs(neighbor.substr(1), k, seen, result);
result += to_string(x);
}
}
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
Цены на все Серверы онлайн! Удобный конфигуратор!
Серверы STSS Flagman✅
Огромный выбор решений 👍
Консультации лучших экспертов 👌
Непревзойденный сервис ❤️
Получить предложение
#реклама
stss.ru
О рекламодателе
3 254
#medium
Задача: 752. Open the Lock
Перед вами замок с 4 круглыми колесами. Каждое колесо имеет 10 слотов: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'. Колеса могут свободно вращаться и оборачиваться: например, мы можем повернуть "9" так, чтобы получился "0", или "0" так, чтобы получился "9". Каждый ход состоит из поворота одного колеса на один слот. Изначально замок начинается с '0000', строки, представляющей состояние 4 колес. Вам дан список тупиков, то есть если замок отобразит любой из этих кодов, колеса замка перестанут вращаться, и вы не сможете его открыть. Учитывая цель, представляющую значение колес, которое позволит отпереть замок, верните минимальное общее количество оборотов, необходимое для открытия замка, или -1, если это невозможно.
Пример:
Input: deadends = ["0201","0101","0102","1212","2002"], target = "0202" Output: 6👨💻 Алгоритм: 1⃣Используйте алгоритм BFS для поиска кратчайшего пути от начального состояния '0000' до целевого состояния, избегая тупиков. Инициализируйте очередь с начальным состоянием '0000' и начальным шагом 0. Используйте множество для отслеживания посещенных состояний, чтобы избежать повторного посещения одного и того же состояния. 2⃣Для каждого состояния в очереди: Проверьте все возможные переходы на следующий шаг, вращая каждое колесо на +1 и -1. Если найденное состояние является целевым, верните количество шагов. Если найденное состояние не является тупиком и не было посещено ранее, добавьте его в очередь и отметьте как посещенное. 3⃣Если очередь пуста и целевое состояние не найдено, верните -1. 😎 Решение:
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
unordered_set<string> dead(deadends.begin(), deadends.end());
queue<pair<string, int>> queue;
queue.push({"0000", 0});
unordered_set<string> visited;
visited.insert("0000");
while (!queue.empty()) {
auto [node, steps] = queue.front();
queue.pop();
if (node == target) {
return steps;
}
if (dead.count(node)) {
continue;
}
for (auto neighbor : neighbors(node)) {
if (!visited.count(neighbor)) {
visited.insert(neighbor);
queue.push({neighbor, steps + 1});
}
}
}
return -1;
}
private:
vector<string> neighbors(const string& node) {
vector<string> res;
for (int i = 0; i < 4; i++) {
string up = node;
up[i] = (node[i] - '0' + 1) % 10 + '0';
res.push_back(up);
string down = node;
down[i] = (node[i] - '0' - 1 + 10) % 10 + '0';
res.push_back(down);
}
return res;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
📺 Уникальная база IT собеседований
456+ реальных собеседований на программиста, тестировщика, аналитика и прочие IT профы.
Есть собесы от ведущих компаний: Сбер, Яндекс, ВТБ, Тинькофф, Озон, Wildberries и т.д.
🎯 Переходи по ссылке и присоединяйся к базе, чтобы прокачать свои шансы на успешное трудоустройство!
3 254
#medium
Задача: 751. IP to CIDR
Дан указатель на начало односвязного списка и два целых числа left и right, где left <= right. Необходимо перевернуть узлы списка, начиная с позиции left и заканчивая позицией right, и вернуть измененный список.
Пример:
Input: ip = "255.0.0.7", n = 10 Output: ["255.0.0.7/32","255.0.0.8/29","255.0.0.16/32"]👨💻 Алгоритм: 1⃣Преобразовать начальный IP-адрес в целое число. 2⃣Пока количество оставшихся IP-адресов n больше нуля: Определить наибольший блок, который начинается с текущего IP-адреса и не превышает количество оставшихся IP-адресов. Добавить этот блок к результату. Увеличить текущий IP-адрес на размер блока. Уменьшить количество оставшихся IP-адресов n. 3⃣Преобразовать блоки обратно в формат CIDR и вернуть их. 😎 Решение:
class Solution {
public:
vector<string> findCidrBlocks(string startIp, int n) {
int start = ipToInt(startIp);
vector<string> result;
while (n > 0) {
int maxSize = 1;
while (maxSize <= start && maxSize <= n) {
maxSize <<= 1;
}
maxSize >>= 1;
while (start % maxSize != 0) {
maxSize >>= 1;
}
result.push_back(cidr(intToIp(start), 32 - bitCount(maxSize - 1) + 1));
start += maxSize;
n -= maxSize;
}
return result;
}
private:
int ipToInt(const string& ip) {
int result = 0;
stringstream ss(ip);
string segment;
for (int i = 0; getline(ss, segment, '.'); ++i) {
result = result * 256 + stoi(segment);
}
return result;
}
string intToIp(int num) {
return to_string((num >> 24) & 255) + "." + to_string((num >> 16) & 255) + "." +
to_string((num >> 8) & 255) + "." + to_string(num & 255);
}
string cidr(const string& ip, int prefixLength) {
return ip + "/" + to_string(prefixLength);
}
int bitCount(int n) {
return (int)log2(n) + 1;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
Repost from easyoffer
На easyoffer 2.0 появится:
🎯 Тренажер "Проработка вопросов"
✅ Метод интервальных повторений и флеш-карточки
✅ Персональный подход изучения на основе ваших ответов
✅ Упор на самые частые вопросы
📌 Интервальные повторения по карточкам это научно доказанный метод эффективного обучения. Каждая карточка – это вопрос, который задают на собеседовании, вы можете выбрать "Не знаю", "Знаю", "Не спрашивать". После ответа вам показывается правильный ответ и возможность изучить вопрос подробнее (примеры ответов других людей). От ваших ответов зависит то, как часто карточки будут показываться на следующей тренировке. Трудные вопросы показываются чаще, простые – реже. Это позволяет бить в слабые места. Кроме того, изначальный порядок карточек зависит от частотности (вероятности встретить вопрос).
🚀 Благодаря этому тренажеру вы сможете очень быстро подготовиться к собеседованию, т.к. фокусируетесь отвечать на самые частые вопросы. Именно так готовился я сам, когда искал первую работу программистом.
Уже в течение недели я объявлю о старте краудфандинговой кампании на сбор финансирования, чтобы ускорить разработку сайта. Все кто поддержит проект до официального релиза получат самые выгодные условия пользования сервисом. А именно 1 год доступа к сайту по цене месячной подписки.
‼️ Очень важно, чтобы как можно больше людей поддержали проект в первые дни, по-этому те кто окажет поддержку первыми получат еще более выгодную стоимость на годовую подписку и существенный 💎 бонус о котором я позже расскажу в этом телеграм канале. Подписывайтесь, чтобы узнать о старте проекта раньше других и воспользоваться лимитированными вознаграждениями.
3 254
Онлайн-магистратура в IT совместно с ИТМО, МИФИ и МФТИ
День открытых дверей
19 марта 19:00 мск | Онлайн
Все программы 2025, общение со студентами и экспертами из вузов и Яндекса. Ответы на вопросы.
Зарегистрироваться
#реклама 16+
practicum.yandex.ru
О рекламодателе
3 254
#medium
Задача: 750. Number Of Corner Rectangles
Дан указатель на начало односвязного списка и два целых числа left и right, где left <= right. Необходимо перевернуть узлы списка, начиная с позиции left и заканчивая позицией right, и вернуть измененный список.
Пример:
Input: grid = [[1,0,0,1,0],[0,0,1,0,1],[0,0,0,1,0],[1,0,1,0,1]] Output: 1👨💻 Алгоритм: 1⃣Пройдите по строкам матрицы. Для каждой пары строк, найдите все столбцы, где оба значения равны 1. 2⃣Подсчитайте количество таких столбцов. Если их больше одного, то они образуют прямоугольники. 3⃣Для каждой пары строк добавьте количество возможных прямоугольников в общий счетчик. 😎 Решение:
class Solution {
public:
int countCornerRectangles(vector<vector<int>>& grid) {
int count = 0;
for (int i = 0; i < grid.size(); i++) {
for (int j = i + 1; j < grid.size(); j++) {
int numPairs = 0;
for (int k = 0; k < grid[0].size(); k++) {
if (grid[i][k] == 1 && grid[j][k] == 1) {
numPairs++;
}
}
if (numPairs > 1) {
count += numPairs * (numPairs - 1) / 2;
}
}
}
return count;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
Ваш сайт = ваши деньги. Что, если завтра его не станет?
Стабильность онлайн-бизнеса напрямую зависит от работы сайта. Если клиенты не смогут оформить заказ, они не будут ждать — уйдут туда, где все работает без сбоев.
Многие думают, что хакеры нападают только на крупные компании. Это миф. Ваши конкуренты могут накрутить ботов или заказать DDoS-атаку, что приведет к потерям прибыли и репутации.
Как защитить сайт и избежать финансовых потерь, расскажут эксперты «Солара» на вебинаре «Безопасный сайт — прибыльный сайт: как хакерские атаки влияют на ваш доход».
Вы узнате:
- Почему важно поддерживать бесперебойную работу веб-ресурса;
- Как киберугрозы наносят ущерб бизнесу;
- Что важно при выборе защиты.
Вас ждут реальные кейсы атак, которые докажут: такие проблемы касаются не только крупных компаний.
Регистрируйтесь!
Зарегистрироваться
#реклама 16+
rt-solar.ru
О рекламодателе
3 254
#medium
Задача: 1404. Number of Steps to Reduce a Number in Binary Representation to One
Дано бинарное представление целого числа в виде строки s. Верните количество шагов, необходимых для его сокращения до 1 по следующим правилам:
Если текущее число четное, его нужно разделить на 2.
Если текущее число нечетное, нужно прибавить к нему 1.
Гарантируется, что для всех тестовых случаев всегда можно достичь единицы.
Пример:
Input: s = "1101" Output: 6 Explanation: "1101" corressponds to number 13 in their decimal representation. Step 1) 13 is odd, add 1 and obtain 14. Step 2) 14 is even, divide by 2 and obtain 7. Step 3) 7 is odd, add 1 and obtain 8. Step 4) 8 is even, divide by 2 and obtain 4. Step 5) 4 is even, divide by 2 and obtain 2. Step 6) 2 is even, divide by 2 and obtain 1.👨💻 Алгоритм: 1⃣Инициализируйте переменную operations значением 0. 2⃣Повторяйте операции, пока длина строки s больше 1: Если последний бит строки s равен 0, это означает, что число четное; примените операцию деления на 2, удалив последний бит. В противном случае это означает, что число, представленное строкой, нечетное; добавьте 1 к числу, изменив строку, чтобы выполнить эту операцию. 3⃣Верните количество операций. 😎 Решение:
class Solution {
public:
int numSteps(string s) {
int operations = 0;
while (s.size() > 1) {
if (s.back() == '0') {
s.pop_back();
} else {
int i = s.size() - 1;
while (i >= 0 && s[i] == '1') {
s[i] = '0';
i--;
}
if (i < 0) {
s.insert(s.begin(), '1');
} else {
s[i] = '1';
}
}
operations++;
}
return operations;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
Крупнейший университет искусственного интеллекта
Приглашаем на бесплатный однодневный интенсив по AI!
Освой искусственный интеллект для профессионального роста: создавай нейросети, автоматизируй бизнес-задачи и зарабатывай на AI-решениях.
✨ 8 000+ студентов со всего мира
✨ 600+ AI-проектов, созданных студентами
✨ Сборная Университета — победители крупнейших AI-хакатонов России
✨ Стажировки в крупнейших компаниях России (РЖД, Ростелеком, РУДН, Совкомбанк, Самолет и другие)
✨ Трудоустраиваем выпускников в крупнейшие компании (Яндекс, ВТБ, Сбербанк, Роскосмос и другие)
Будем рады видеть тебя в наших рядах!
Узнать больше
#реклама 16+
neural-university.ru
О рекламодателе
3 254
#hard
Задача: 1402. Reducing Dishes
Шеф-повар собрал данные об уровне удовлетворенности от своих n блюд. Шеф может приготовить любое блюдо за 1 единицу времени.
Коэффициент удовольствия от блюда определяется как время, затраченное на приготовление этого блюда вместе с предыдущими блюдами, умноженное на уровень удовлетворенности от этого блюда, то есть time[i] * satisfaction[i].
Верните максимальную сумму коэффициентов удовольствия, которую шеф-повар может получить после приготовления некоторого количества блюд.
Блюда можно готовить в любом порядке, и шеф может отказаться от некоторых блюд, чтобы достичь максимального значения.
Пример:
Input: satisfaction = [-1,-8,0,5,-9] Output: 14 Explanation: After Removing the second and last dish, the maximum total like-time coefficient will be equal to (-1*1 + 0*2 + 5*3 = 14). Each dish is prepared in one unit of time.👨💻 Алгоритм: 1⃣Отсортируйте массив satisfaction в порядке возрастания. 2⃣Создайте таблицу мемоизации memo размером N x N и инициализируйте все значения -1, что будет означать, что ответ для всех состояний еще не рассчитан. 3⃣Реализуйте функцию, которая вызывается с параметрами index = 0 и time = 1, чтобы найти ответ: Если достигнут конец массива, т.е. index == satisfaction.length, верните 0, так как больше нет блюд для приготовления и нельзя получить дополнительное значение. Если значение в массиве memo для пары {index, time} не равно -1, верните это значение, так как это подразумевает, что данная подзадача уже была решена; поэтому рекурсивный вызов не требуется, и можно вернуть сохраненное значение из таблицы memo. Рассчитайте максимум из двух вариантов: добавьте значение коэффициента для данного блюда satisfaction[index] * time к рекурсивному результату с index = index + 1 и time = time + 1. Пропустите текущее блюдо и сделайте рекурсивный вызов для index = index + 1 и time = time. 😎 Решение:
class Solution {
public:
int findMaxSatisfaction(vector<int>& satisfaction, vector<vector<int>>& memo, int index, int time) {
if (index == satisfaction.size()) return 0;
if (memo[index][time] != -1) return memo[index][time];
return memo[index][time] = max(satisfaction[index] * time + findMaxSatisfaction(satisfaction, memo, index + 1, time + 1),
findMaxSatisfaction(satisfaction, memo, index + 1, time));
}
int maxSatisfaction(vector<int>& satisfaction) {
sort(satisfaction.begin(), satisfaction.end());
vector<vector<int>> memo(satisfaction.size() + 1, vector<int>(satisfaction.size() + 1, -1));
return findMaxSatisfaction(satisfaction, memo, 0, 1);
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
+5
Аудит СУБД со скидкой 50%: проверьте базы данных!
Как работает ваша СУБД? Уверены, что она справляется с нагрузкой и не тормозит бизнес-процессы? Команда РДТЕХ предлагает профессиональный аудит СУБД со скидкой 50%!
💻 Мы проанализируем ваши базы данных на Oracle, PostgreSQL или Microsoft SQL Server, выявим слабые места и дадим рекомендации по оптимизации. Наши эксперты с опытом внедрения и поддержки СУБД помогут:
✅ Ускорить работу системы;
✅ Снизить риски сбоев;
✅ Повысить отказоустойчивость.
✨ Акция действует до конца марта! Успейте проверить свою СУБД и сэкономить. Не упустите шанс улучшить производительность ваших баз данных!
Узнать больше
#реклама
rdtex.ru
О рекламодателе
3 254
#easy
Задача: 748. Shortest Completing Word
Вам дан целочисленный массив nums, в котором наибольшее целое число уникально. Определите, является ли наибольший элемент массива по крайней мере в два раза больше всех остальных чисел в массиве. Если да, то верните индекс самого большого элемента, в противном случае верните -1.
Пример:
Input: licensePlate = "1s3 PSt", words = ["step","steps","stripe","stepple"] Output: "steps"👨💻 Алгоритм: 1⃣Извлечь все буквы из licensePlate, игнорируя цифры и пробелы, и создать словарь для подсчета частоты каждой буквы. 2⃣Пройти по массиву words, проверяя каждое слово на соответствие требованиям. 3⃣Найти самое короткое завершающее слово среди подходящих. 😎 Решение:
class Solution {
public:
string shortestCompletingWord(string licensePlate, vector<string>& words) {
unordered_map<char, int> licenseCount = getCharCount(licensePlate);
string result;
for (const string& word : words) {
if (isCompletingWord(word, licenseCount)) {
if (result.empty() || word.length() < result.length()) {
result = word;
}
}
}
return result;
}
private:
unordered_map<char, int> getCharCount(const string& s) {
unordered_map<char, int> count;
for (char c : s) {
if (isalpha(c)) {
count[tolower(c)]++;
}
}
return count;
}
bool isCompletingWord(const string& word, const unordered_map<char, int>& licenseCount) {
unordered_map<char, int> wordCount;
for (char c : word) {
wordCount[c]++;
}
for (const auto& entry : licenseCount) {
if (wordCount[entry.first] < entry.second) {
return false;
}
}
return true;
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
Дарим подписку на Яндекс Музыку
Ответьте на 1 вопрос и Яндекс Музыка для вас и 3-х ваших близких 14 дней бесплатно.
Кинопоиск и Яндекс Книги тоже в подписке.
Попробуйте сейчас❤️
Попробовать
#реклама 18+
music.yandex.ru
О рекламодателе
Реклама на Яндексе
3 254
#easy
Задача: 746. Min Cost Climbing Stairs
Вам дан целочисленный массив cost, где cost[i] - стоимость i-й ступеньки на лестнице. После оплаты стоимости вы можете подняться на одну или две ступеньки. Вы можете начать со ступеньки с индексом 0 или со ступеньки с индексом 1. Верните минимальную стоимость достижения вершины этажа.
Пример:
Input: cost = [10,15,20] Output: 15👨💻 Алгоритм: 1⃣Создать массив dp, где dp[i] хранит минимальную стоимость достижения i-й ступеньки. 2⃣Инициализировать dp[0] и dp[1] как cost[0] и cost[1] соответственно. Заполнить dp используя минимальную стоимость подъема с предыдущих ступенек. 3⃣Вернуть минимальную стоимость достижения вершины. 😎 Решение:
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
vector<int> dp = cost;
for (int i = 2; i < n; i++) {
dp[i] += min(dp[i - 1], dp[i - 2]);
}
return min(dp[n - 1], dp[n - 2]);
}
};
Ставь 👍 и забирай 📚 Базу знаний3 254
UserGate Open Conf 17 / 04 / 2025
⚡ ИТ-конференция про защиту в открытую.
Здесь мы создаем площадку для открытого диалога между заказчиками, партнерами, экспертами и специалистами в сфере продуктов, технологий и услуг информационной безопасности.
Что мы готовим для вас:
- аналитические данные исследования рынка информационной безопасности;
- обзор новых видов и эволюции киберугроз с разбором кейсов по борьбе с ними;
- планы внедрения новых фич и обновлений продуктов экосистемы UserGate;
- 30+ продуктовых, партнерских и клиентских докладов;
- нетворкинг, продуктовые демо, обмен опытом и консультации экспертов ИБ;
- ответы на любые вопросы и сбор обратной связи о работе продуктов и устройств UserGate.
Зарегистрироваться
#реклама
openconf.usergate.com
О рекламодателе
3 254
#hard
Задача: 745. Prefix and Suffix Search
Создайте специальный словарь, в котором поиск слов осуществляется по префиксу и суффиксу. Реализуйте класс WordFilter: WordFilter(string[] words) Инициализирует объект со словами в словаре. f(string pref, string suff) Возвращает индекс слова в словаре, которое имеет префикс pref и суффикс suff. Если существует более одного допустимого индекса, возвращается наибольший из них. Если в словаре нет такого слова, возвращается -1.
Пример:
Input: letters = ["c","f","j"], target = "a" Output: "c"👨💻 Алгоритм: 1⃣Сохраните слова и их индексы в словаре. 2⃣Создайте объединенные ключи, состоящие из префиксов и суффиксов для всех возможных комбинаций. 3⃣Реализуйте функцию поиска, которая ищет наибольший индекс слова по префиксу и суффиксу. 😎 Решение:
class WordFilter {
public:
WordFilter(vector<string>& words) {
for (int index = 0; index < words.size(); ++index) {
string word = words[index];
int length = word.length();
for (int prefixLength = 1; prefixLength <= length; ++prefixLength) {
for (int suffixLength = 1; suffixLength <= length; ++suffixLength) {
string prefix = word.substr(0, prefixLength);
string suffix = word.substr(length - suffixLength);
string key = prefix + "#" + suffix;
prefixSuffixMap[key] = index;
}
}
}
}
int f(string pref, string suff) {
string key = pref + "#" + suff;
return prefixSuffixMap.count(key) ? prefixSuffixMap[key] : -1;
}
private:
unordered_map<string, int> prefixSuffixMap;
};
Ставь 👍 и забирай 📚 Базу знаний3 254
Реальный кейс: создание REST API движка на С++
История, полная ошибок и боли белорусских разработчиков, которая поможет вам избежать типичных проблем при создании REST API.
Узнайте, стал ли этот проект успешным, на бесплатном вебинаре «Движок REST API на C++. Кейс компании СКБ Радиотехпроект (SKB RTP)».
Разберём:
1. Зачем писать свой движок REST
2. Swagger в C++ как fail
3. Почему Rest это не просто url — это философия
📆Когда: 25 марта в 19:00
Спикер: Юрий Вашинко, Tech Lead/Lead Developer
👉 Занять место на вебинаре — через бота.
В конце вебинара — подарок🎁
Вебинар проходит в рамках курса «Разработчик С++20».
#реклама
О рекламодателе
erid: 2W5zFHDLWYp
¡Ya disponible! Investigación de Telegram 2025 — los principales insights del año 
