PHP | LeetCode
1.51K subscribers
167 photos
1.05K links
Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.iss.one/+pSDoLEZBQRZlNmFi
Вопросы собесов t.iss.one/+RJaDhjYaQDo2Njcy
Вакансии t.iss.one/+J-DKRUtjUgMxZGNi
Download Telegram
Задача: 628. Maximum Product of Three Numbers
Сложность: medium

Задав целочисленный массив nums, найдите три числа, произведение которых максимально, и верните максимальное произведение.

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


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

1⃣Отсортируйте массив nums.

2⃣Найдите два возможных максимальных произведения: Произведение трех наибольших элементов массива. Произведение двух наименьших (отрицательных) и одного наибольшего элемента массива.

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

😎 Решение:
function maximumProduct($nums) {
sort($nums);
$n = count($nums);
$max1 = $nums[$n - 1] * $nums[$n - 2] * $nums[$n - 3];
$max2 = $nums[0] * $nums[1] * $nums[$n - 1];
return max($max1, $max2);
}


Ставь 👍 и забирай 📚 Базу знаний
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.

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

function diameterOfBinaryTree($root) {
$this->diameter = 0;
$this->longestPath($root);
return $this->diameter;
}

private function longestPath($node) {
if ($node === null) return 0;

$leftPath = $this->longestPath($node->left);
$rightPath = $this->longestPath($node->right);

$this->diameter = max($this->diameter, $leftPath + $rightPath);

return max($leftPath, $rightPath) + 1;
}
}


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

У вас есть граф из n узлов, помеченных от 0 до n - 1. Вам даны целое число n и список рёбер, где edges[i] = [ai, bi] указывает на то, что существует неориентированное ребро между узлами ai и bi в графе.
Верните true, если рёбра данного графа образуют допустимое дерево, и false в противном случае.

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


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

1⃣Проверьте, что количество рёбер равно n - 1. Если нет, верните false.

2⃣Используйте итеративный обход в глубину (DFS) для проверки связности графа и отсутствия циклов. Создайте стек для хранения узлов для посещения и множество для отслеживания посещённых узлов. Начните с узла 0.

3⃣Если все узлы посещены и циклы не обнаружены, верните true. В противном случае, верните false.

😎 Решение:
class Solution {
function validTree($n, $edges) {
if (count($edges) != $n - 1) {
return false;
}

$adjList = array_fill(0, $n, []);
foreach ($edges as $edge) {
$adjList[$edge[0]][] = $edge[1];
$adjList[$edge[1]][] = $edge[0];
}

$parent = [0 => -1];
$queue = [0];

while (!empty($queue)) {
$node = array_shift($queue);
foreach ($adjList[$node] as $neighbor) {
if ($neighbor == $parent[$node]) {
continue;
}
if (isset($parent[$neighbor])) {
return false;
}
$parent[$neighbor] = $node;
$queue[] = $neighbor;
}
}

return count($parent) == $n;
}
}


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

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

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


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

1⃣Отсортируйте массив nums.

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

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

😎 Решение:
function triangleNumber($nums) {
sort($nums);
$n = count($nums);
$count = 0;

for ($k = $n - 1; $k >= 2; $k--) {
$i = 0;
$j = $k - 1;
while ($i < $j) {
if ($nums[$i] + $nums[$j] > $nums[$k]) {
$count += $j - $i;
$j--;
} else {
$i++;
}
}
}

return $count;
}


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

Факториал целого положительного числа n - это произведение всех целых положительных чисел, меньших или равных n. Например, факториал(10) = 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1.
Мы составляем неуклюжий факториал, используя целые числа в порядке убывания, заменяя операции умножения на фиксированную последовательность операций с умножением "*", делением "/", сложением "+" и вычитанием "-" в этом порядке. Например, clumsy(10) = 10 * 9 / 8 + 7 - 6 * 5 / 4 + 3 - 2 * 1. Однако эти операции по-прежнему применяются с использованием обычного порядка операций арифметики. Мы выполняем все шаги умножения и деления перед шагами сложения и вычитания, а шаги умножения и деления выполняются слева направо. Кроме того, деление, которое мы используем, является делением с полом, так что 10 * 9 / 8 = 90 / 8 = 11. Учитывая целое число n, верните неуклюжий факториал n.

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


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

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

2⃣Выполнение операций в цикле:
Создайте цикл, который будет обрабатывать числа от n до 1 в порядке убывания.
В цикле выполняйте операции *, /, +, и - последовательно.
Обновляйте текущий результат на каждом шаге в зависимости от остатка от деления текущего индекса на 4.

3⃣Учет оставшихся операций и возврат результата:
После завершения цикла добавьте или вычтите оставшиеся числа (если есть) к результату.
Верните окончательный результат.

😎 Решение:
class Solution {
function clumsy($n) {
if ($n == 0) return 0;
if ($n == 1) return 1;
if ($n == 2) return 2 * 1;
if ($n == 3) return 3 * 2 / 1;

$res = $n * ($n - 1) / ($n - 2);
$n -= 3;
if ($n > 0) $res += $n--;

while ($n > 0) {
$res -= $n * ($n - 1) / ($n - 2);
$n -= 3;
if ($n > 0) $res += $n--;
}

return $res;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1493. Longest Subarray of 1's After Deleting One Element
Сложность: medium

Дан бинарный массив nums, из которого следует удалить один элемент.

Верните размер самой длинной непустой подмассивы, содержащей только 1, в результирующем массиве. Верните 0, если такого подмассива не существует.

Пример:
Input: nums = [0,1,1,1,0,1,1,0,1]
Output: 5
Explanation: After deleting the number in position 4, [0,1,1,1,1,1,0,1] longest subarray with value of 1's is [1,1,1,1,1].


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

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

2⃣Итерация по массиву:
При каждом элементе увеличиваем zeroCount, если это ноль.
Если zeroCount превышает 1, сокращаем окно, перемещая левую границу вправо и уменьшая zeroCount, пока количество нулей не станет меньше или равно 1.
Обновляем longestWindow текущей длиной окна i - start.

3⃣Возврат результата:
Вернуть longestWindow.

😎 Решение:
class Solution {
function longestSubarray($nums) {
$zeroCount = 0;
$longestWindow = 0;
$start = 0;

for ($i = 0; $i < count($nums); $i++) {
if ($nums[$i] == 0) {
$zeroCount++;
}

while ($zeroCount > 1) {
if ($nums[$start] == 0) {
$zeroCount--;
}
$start++;
}

$longestWindow = max($longestWindow, $i - $start);
}

return $longestWindow;
}
}


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

Дан массив интервалов времени встреч, где intervals[i] = [starti, endi]. Определите, может ли человек посетить все встречи.

Пример:
Input: intervals = [[0,30],[5,10],[15,20]]
Output: false


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

1⃣Создайте функцию для проверки перекрытия двух интервалов:
Возвращайте true, если начало одного интервала находится внутри другого интервала.

2⃣Проверьте каждый интервал с каждым другим интервалом:
Если найдено перекрытие, верните false.

3⃣Если все интервалы проверены и перекрытий не найдено, верните true.

😎 Решение:
class Solution {
function overlap($interval1, $interval2) {
return ($interval1[0] >= $interval2[0] && $interval1[0] < $interval2[1]) ||
($interval2[0] >= $interval1[0] && $interval2[0] < $interval1[1]);
}

function canAttendMeetings($intervals) {
for ($i = 0; $i < count($intervals); $i++) {
for ($j = $i + 1; $j < count($intervals); $j++) {
if ($this->overlap($intervals[$i], $intervals[$j])) {
return false;
}
}
}
return true;
}
}


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

Даны две разреженные матрицы mat1 размером m x k и mat2 размером k x n. Верните результат перемножения матриц mat1 x mat2. Вы можете предположить, что умножение всегда возможно.

Пример:
Input: mat1 = [[1,0,0],[-1,0,3]], mat2 = [[7,0,0],[0,0,0],[0,0,1]]
Output: [[7,0,0],[-7,0,3]]


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

1⃣Инициализация результирующей матрицы
Создайте результирующую матрицу result размером m x n, заполненную нулями.

2⃣Хранение ненулевых элементов
Пройдите по каждой строке матрицы mat1 и сохраните индексы и значения ненулевых элементов в хеш-карте mat1_map. Пройдите по каждой колонке матрицы mat2 и сохраните индексы и значения ненулевых элементов в хеш-карте mat2_map.

3⃣Вычисление произведения
Для каждой строки i в mat1 и для каждой колонки j в mat2: Если в mat1_map есть ненулевой элемент в строке i и в mat2_map есть ненулевой элемент в колонке j с одинаковым индексом k, добавьте произведение этих элементов к result[i][j].

😎 Решение:
class Solution {
function multiply($mat1, $mat2) {
$n = count($mat1);
$k = count($mat1[0]);
$m = count($mat2[0]);

$ans = array_fill(0, $n, array_fill(0, $m, 0));

for ($rowIndex = 0; $rowIndex < $n; $rowIndex++) {
for ($elementIndex = 0; $elementIndex < $k; $elementIndex++) {
if ($mat1[$rowIndex][$elementIndex] != 0) {
for ($colIndex = 0; $colIndex < $m; $colIndex++) {
$ans[$rowIndex][$colIndex] += $mat1[$rowIndex][$elementIndex] * $mat2[$elementIndex][$colIndex];
}
}
}
}

return $ans;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1047. Remove All Adjacent Duplicates In String
Сложность: easy

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

Пример:
Input: stones = [2,7,4,1,8,1]
Output: 1


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

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

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

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

😎 Решение:
function removeDuplicates($s) {
$stack = [];
for ($i = 0; $i < strlen($s); $i++) {
$char = $s[$i];
if (!empty($stack) && end($stack) === $char) {
array_pop($stack);
} else {
$stack[] = $char;
}
}
return implode('', $stack);
}


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

Вам дана строка s и целое число k. Вы можете выбрать любой символ строки и заменить его на любой другой заглавный английский символ. Вы можете выполнить эту операцию не более k раз.

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

Пример:
Input: s = "ABAB", k = 2
Output: 4
Explanation: Replace the two 'A's with two 'B's or vice versa.


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

1⃣Определите диапазон поиска. Минимальная длина подстроки с одинаковыми символами всегда равна 1 (назовем ее min), а максимальная длина подстроки может быть равна длине данной строки (назовем ее max). Ответ будет лежать в диапазоне [min, max] (включительно).

2⃣Инициализируйте две переменные lo и hi для бинарного поиска. lo всегда указывает на длину допустимой строки, а hi - на недопустимую длину. Изначально lo равно 1, а hi равно max+1.

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

😎 Решение:
class Solution {
function characterReplacement
class Solution {
function characterReplacement($s, $k) {
$lo = 1;
$hi = strlen($s) + 1;

while ($lo + 1 < $hi) {
$mid = $lo + intval(($hi - $lo) / 2);
if ($this->canMakeValidSubstring($s, $mid, $k)) {
$lo = $mid;
} else {
$hi = $mid;
}
}

return $lo;
}

private function canMakeValidSubstring($s, $substringLength, $k) {
$freqMap = array_fill(0, 26, 0);
$maxFrequency = 0;
$start = 0;

for ($end = 0; $end < strlen($s); $end++) {
$freqMap[ord($s[$end]) - ord('A')]++;

if ($end + 1 - $start > $substringLength) {
$freqMap[ord($s[$start]) - ord('A')]--;
$start++;
}

$maxFrequency = max($maxFrequency, $freqMap[ord($s[$end]) - ord('A')]);
if ($substringLength - $maxFrequency <= $k) {
return true;
}
}

return false;
}
}


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

Наш герой Тимо атакует врага Эшу ядовитыми атаками! Когда Тимо атакует Эшу, она оказывается отравленной на ровно duration секунд. Более формально, атака в секунду t означает, что Эша будет отравлена в течение интервала времени [t, t + duration - 1] включительно. Если Тимо атакует снова до окончания эффекта яда, таймер для него сбрасывается, и эффект яда закончится через duration секунд после новой атаки.
Вам дано неубывающее целое число timeSeries, где timeSeries[i] обозначает, что Тимо атакует Эшу во вторую timeSeries[i], и целое число duration.
Верните общее количество секунд, в течение которых Эша была отравлена.

Пример:
Input: timeSeries = [1,4], duration = 2
Output: 4
Explanation: Teemo's attacks on Ashe go as follows:
- At second 1, Teemo attacks, and Ashe is poisoned for seconds 1 and 2.
- At second 4, Teemo attacks, and Ashe is poisoned for seconds 4 and 5.
Ashe is poisoned for seconds 1, 2, 4, and 5, which is 4 seconds in total.


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

1⃣Инициализация
Инициализируйте переменную total для хранения общего времени, в течение которого Эша была отравлена. Проверьте, если массив timeSeries пуст, верните 0.

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

3⃣Возврат результата
Верните сумму total и duration, чтобы учесть последнюю атаку.

😎 Решение:
class Solution {
function findPoisonedDuration($timeSeries, $duration) {
$n = count($timeSeries);
if ($n == 0) return 0;

$total = 0;
for ($i = 0; $i < $n - 1; $i++) {
$total += min($timeSeries[$i + 1] - $timeSeries[$i], $duration);
}
return $total + $duration;
}
}


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

Дана строка s, представляющая выражение. Вычислите это выражение и верните его значение.
Целочисленное деление должно округляться к нулю.
Вы можете предположить, что данное выражение всегда является допустимым. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].
Примечание: Запрещено использовать какие-либо встроенные функции, которые вычисляют строки как математические выражения, такие как eval().

Пример:
Input: s = "3+2*2"
Output: 7


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

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

2⃣Если операция сложения (+) или вычитания (-), добавляем lastNumber к результату вместо того, чтобы помещать его в стек. Текущее значение currentNumber будет обновлено на lastNumber для следующей итерации.

3⃣Если операция умножения (*) или деления (/), вычисляем выражение lastNumber * currentNumber и обновляем lastNumber с результатом выражения. Это значение будет добавлено к результату после сканирования всей строки.

😎 Решение:
class Solution {
function calculate($s) {
$length = strlen($s);
if ($length == 0) return 0;
$currentNumber = 0;
$lastNumber = 0;
$result = 0;
$sign = '+';

for ($i = 0; $i < $length; $i++) {
$currentChar = $s[$i];
if (ctype_digit($currentChar)) {
$currentNumber = ($currentNumber * 10) + intval($currentChar);
}
if (!ctype_digit($currentChar) && !ctype_space($currentChar) || $i == $length - 1) {
if ($sign == '+' || $sign == '-') {
$result += $lastNumber;
$lastNumber = ($sign == '+') ? $currentNumber : -$currentNumber;
} else if ($sign == '*') {
$lastNumber *= $currentNumber;
} else if ($sign == '/') {
$lastNumber /= $currentNumber;
}
$sign = $currentChar;
$currentNumber = 0;
}
}
$result += $lastNumber;
return $result;
}
}


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

😎 Решение:
function minMalwareSpread($graph, $initial) {
function dfs($graph, $node, &$infected) {
for ($neighbor = 0; $neighbor < count($graph); $neighbor++) {
if ($graph[$node][$neighbor] == 1 && !in_array($neighbor, $infected)) {
$infected[] = $neighbor;
dfs($graph, $neighbor, $infected);
}
}
}

$n = count($graph);
$initialSet = $initial;
sort($initial);
$minInfected = PHP_INT_MAX;
$bestNode = $initial[0];

foreach ($initial as $node) {
$infected = $initialSet;
$infected = array_diff($infected, [$node]);
foreach ($initialSet as $i) {
if ($i != $node) {
dfs($graph, $i, $infected);
}
}
if (count($infected) < $minInfected) {
$minInfected = count($infected);
$bestNode = $node;
}
}

return $bestNode;
}


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

Вам дана строка s и массив пар индексов в строке pairs, где pairs[i] = [a, b] указывает на 2 индекса (начиная с 0) в строке.
Вы можете менять местами символы в любой паре индексов в заданных парах любое количество раз.
Верните лексикографически наименьшую строку, которую можно получить после выполнения перестановок.

Пример:
Input: s = "dcab", pairs = [[0,3],[1,2]]
Output: "bacd"
Explaination:
Swap s[0] and s[3], s = "bcad"
Swap s[1] and s[2], s = "bacd"


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

1⃣Создание списка смежности:
Итеративно пройдитесь по парам и создайте список смежности adj, где adj[source] содержит все смежные вершины вершины source.

2⃣Обход графа и сбор индексов и символов:
Итеративно пройдитесь по индексам от 0 до s.size() - 1. Для каждого индекса vertex:
- выполните DFS, если вершина еще не посещена (visited[vertex] = false).
- во время выполнения DFS сохраняйте vertex в список indices и символ s[vertex] в список characters.

3⃣Сортировка и построение результирующей строки:
Отсортируйте списки indices и characters.
Пройдитесь по индексам и символам, и разместите i-й символ в i-й индекс результирующей строки smallestString.
Верните smallestString.

😎 Решение:
class Solution {
function smallestStringWithSwaps($s, $pairs) {
$n = strlen($s);
$adj = array_fill(0, $n, []);
foreach ($pairs as $pair) {
$adj[$pair[0]][] = $pair[1];
$adj[$pair[1]][] = $pair[0];
}

$visited = array_fill(0, $n, false);
$sArray = str_split($s);

function dfs($node, &$adj, &$visited, &$sArray, &$indices, &$chars) {
$visited[$node] = true;
$indices[] = $node;
$chars[] = $sArray[$node];
foreach ($adj[$node] as $neighbor) {
if (!$visited[$neighbor]) {
dfs($neighbor, $adj, $visited, $sArray, $indices, $chars);
}
}
}

for ($i = 0; $i < $n; $i++) {
if (!$visited[$i]) {
$indices = [];
$chars = [];
dfs($i, $adj, $visited, $sArray, $indices, $chars);
sort($indices);
sort($chars);
for ($j = 0; $j < count($indices); $j++) {
$sArray[$indices[$j]] = $chars[$j];
}
}
}

return implode('', $sArray);
}
}


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

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

Пример:
Input: root = [10,5,15,1,8,null,7]
Output: 3
Explanation: The Largest BST Subtree in this case is the highlighted one. The return value is the subtree's size, which is 3.


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

1⃣Пост-упорядоченный обход дерева:
Обходите каждую ноду дерева в пост-упорядоченном порядке (left-right-root). Это позволит гарантировать, что обе поддеревья ноды уже проверены на соответствие критериям BST перед проверкой самой ноды.

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

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

😎 Решение:
class TreeNode {
public $val;
public $left;
public $right;
function __construct($val = 0, $left = null, $right = null) {
$this->val = $val;
$this->left = $left;
$this->right = $right;
}
}

class NodeValue {
public $minNode;
public $maxNode;
public $maxSize;

function __construct($minNode, $maxNode, $maxSize) {
$this->minNode = $minNode;
$this->maxNode = $maxNode;
$this->maxSize = $maxSize;
}
}

class Solution {
private function largestBSTSubtreeHelper($root) {
if ($root === null) {
return new NodeValue(PHP_INT_MAX, PHP_INT_MIN, 0);
}

$left = $this->largestBSTSubtreeHelper($root->left);
$right = $this->largestBSTSubtreeHelper($root->right);

if ($left->maxNode < $root->val && $root->val < $right->minNode) {
return new NodeValue(min($root->val, $left->minNode), max($root->val, $right->maxNode),
$left->maxSize + $right->maxSize + 1);
}

return new NodeValue(PHP_INT_MIN, PHP_INT_MAX, max($left->maxSize, $right->maxSize));
}

function largestBSTSubtree($root) {
return $this->largestBSTSubtreeHelper($root)->maxSize;
}
}


Ставь 👍 и забирай 📚 Базу знаний
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 как результат.

😎 Решение:
class Solution {
public function getSkyline($buildings) {
$edgeSet = [];
foreach ($buildings as $building) {
$left = $building[0];
$right = $building[1];
$edgeSet[$left] = true;
$edgeSet[$right] = true;
}
$edges = array_keys($edgeSet);
sort($edges);

$edgeIndexMap = [];
foreach ($edges as $index => $edge) {
$edgeIndexMap[$edge] = $index;
}

$heights = array_fill(0, count($edges), 0);

foreach ($buildings as $building) {
$left = $building[0];
$right = $building[1];
$height = $building[2];
$leftIndex = $edgeIndexMap[$left];
$rightIndex = $edgeIndexMap[$right];

for ($idx = $leftIndex; $idx < $rightIndex; ++$idx) {
$heights[$idx] = max($heights[$idx], $height);
}
}

$answer = [];

foreach ($heights as $i => $currHeight) {
$currPos = $edges[$i];

if (empty($answer) || end($answer)[1] != $currHeight) {
$answer[] = [$currPos, $currHeight];
}
}
return $answer;
}
}


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

Вам дан двоичный массив nums (индексированный 0). Мы определяем xi как число, двоичным представлением которого является подмассив nums[0..i] (от старшего бита к младшему). Например, если nums = [1,0,1], то x0 = 1, x1 = 2 и x2 = 5. Верните массив булевых чисел answer, где answer[i] истинно, если xi делится на 5.

Пример:
Input: nums = [0,1,1]
Output: [true,false,false]


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

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

2⃣Итерация по массиву:
Пройдите по всем элементам массива nums. Для каждого элемента:
Обновите значение x, учитывая текущий бит.
Проверяйте, делится ли x на 5, и добавьте результат (true или false) в массив answer.
Чтобы избежать переполнения, используйте модуль 5 для переменной x.

3⃣Возврат результата:
Верните массив answer с результатами проверки делимости на 5.

😎 Решение:
class Solution {
function prefixesDivBy5($nums) {
$x = 0;
$answer = [];
foreach ($nums as $num) {
$x = ($x * 2 + $num) % 5;
$answer[] = $x == 0;
}
return $answer;
}
}


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

Вам даны два целочисленных массива nums1 и nums2. Запишем целые числа nums1 и nums2 (в том порядке, в котором они даны) на двух отдельных горизонтальных линиях. Мы можем провести соединительные линии: прямую линию, соединяющую два числа nums1[i] и nums2[j] так, что: nums1[i] == nums2[j], и проведенная линия не пересекает никакую другую соединительную (негоризонтальную) линию. Обратите внимание, что соединительная линия не может пересекаться даже в конечных точках (т.е, каждое число может принадлежать только одной соединительной линии). Верните максимальное количество соединительных линий, которые мы можем нарисовать таким образом.

Пример:
Input: nums1 = [1,4,2], nums2 = [1,2,4]
Output: 2


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

1⃣Определение задачи как задачи о нахождении наибольшей общей подпоследовательности (LCS):
Эта задача является классической задачей динамического программирования, где нам нужно найти максимальную длину наибольшей общей подпоследовательности (LCS) между nums1 и nums2.

2⃣Построение таблицы динамического программирования:
Создайте двумерный массив dp, где dp[i][j] будет представлять длину наибольшей общей подпоследовательности для подмассивов nums1[0..i-1] и nums2[0..j-1].
Инициализируйте первый ряд и первый столбец нулями, так как если один из массивов пуст, LCS также будет пустым.

3⃣Заполнение таблицы динамического программирования:
Пройдите по элементам массивов nums1 и nums2. Если текущие элементы совпадают, увеличьте значение ячейки dp[i][j] на 1 от диагонального значения dp[i-1][j-1]. Если не совпадают, установите значение ячейки dp[i][j] как максимальное из значений dp[i-1][j] и dp[i][j-1].
Результат будет находиться в ячейке dp[nums1.length][nums2.length].

😎 Решение:
function allCellsDistOrder($rows, $cols, $rCenter, $cCenter) {
$cells = [];

for ($r = 0; $r < $rows; $r++) {
for ($c = 0; $c < $cols; $c++) {
$distance = abs($r - $rCenter) + abs($c - $cCenter);
$cells[] = [$distance, $r, $c];
}
}

usort($cells, function($a, $b) {
return $a[0] <=> $b[0];
});

return array_map(function($cell) {
return [$cell[1], $cell[2]];
}, $cells);
}


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

Нам дан список schedule of employees, который представляет собой рабочее время каждого сотрудника. У каждого сотрудника есть список непересекающихся интервалов, и эти интервалы расположены в отсортированном порядке. Верните список конечных интервалов, представляющих общее свободное время положительной длины для всех сотрудников, также в отсортированном порядке. (Хотя мы представляем интервалы в форме [x, y], объекты внутри них являются интервалами, а не списками или массивами. Например, schedule[0][0].start = 1, schedule[0][0].end = 2, а schedule[0][0][0] не определено).Также мы не будем включать в наш ответ интервалы типа [5, 5], так как они имеют нулевую длину.

Пример:
Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]]
Output: [[3,4]]


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

1⃣Объедините все интервалы всех сотрудников в один список и отсортируйте его по начальным временам.

2⃣Объедините пересекающиеся интервалы в один.

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

😎 Решение:
class Interval {
public $start;
public $end;
function __construct($start, $end) {
$this->start = $start;
$this->end = $end;
}
}

function employeeFreeTime($schedule) {
$intervals = [];
foreach ($schedule as $employee) {
$intervals = array_merge($intervals, $employee);
}

usort($intervals, function($a, $b) {
return $a->start - $b->start;
});

$merged = [];
foreach ($intervals as $interval) {
if (empty($merged) || end($merged)->end < $interval->start) {
$merged[] = $interval;
} else {
end($merged)->end = max(end($merged)->end, $interval->end);
}
}

$freeTime = [];
for ($i = 1; $i < count($merged); $i++) {
if ($merged[$i]->start > $merged[$i - 1]->end) {
$freeTime[] = new Interval($merged[$i - 1]->end, $merged[$i]->start);
}
}

return $freeTime;
}


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

Если задан целочисленный массив arr, верните количество различных побитовых ИЛИ всех непустых подмассивов arr. Побитовое ИЛИ подмассива - это побитовое ИЛИ каждого целого числа в подмассиве. Побитовым ИЛИ подмассива одного целого числа является это целое число. Подмассив - это непрерывная непустая последовательность элементов в массиве.

Пример:
Input: arr = [0]
Output: 1


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

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

2⃣Для каждого элемента массива, вычислить побитовое ИЛИ всех подмассивов, начинающихся с этого элемента.
Добавить результат каждого вычисления в множество.

3⃣Вернуть размер множества.

😎 Решение:
function subarrayBitwiseORs($arr) {
$result = [];
$current = [];
foreach ($arr as $num) {
$next = [$num];
foreach ($current as $x) {
$next[] = $x | $num;
}
$current = array_unique($next);
foreach ($current as $x) {
$result[$x] = true;
}
}
return count($result);
}


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