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
Задача: 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
Задача: 1167. Minimum Cost to Connect Sticks
Сложность: medium

У вас есть несколько палочек с положительными целыми длинами. Эти длины даны в виде массива sticks, где sticks[i] — длина i-й палочки.

Вы можете соединить любые две палочки длиной x и y в одну палочку, заплатив стоимость x + y. Вы должны соединить все палочки, пока не останется только одна палочка.

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

Пример:
Input: sticks = [5]
Output: 0
Explanation: There is only one stick, so you don't need to do anything. The total cost is 0.


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

1⃣Всегда выбирайте две самые маленькие палочки для соединения и продолжайте делать это, пока не останется только одна палочка. Рассмотрим 4 палочки следующих длин: sticks=[a1, a2, a3, a4]. Попробуем соединить их слева направо. После первого соединения у нас будет: sticks=[(a1 + a2), a3, a4], стоимость=(a1 + a2). После второго соединения у нас будет: sticks=[(a1 + a2 + a3), a4], стоимость=(a1 + a2)+(a1 + a2 + a3). И, наконец, последняя палочка будет выглядеть так: sticks=[(a1 + a2 + a3 + a4)], стоимость=(a1 + a2)+(a1 + a2 + a3)+(a1 + a2 + a3 + a4).

2⃣Итоговая стоимость может быть переписана следующим образом: стоимость=(3a1 + 3a2 + 2a3 + a4). Как видим, палочки, которые соединяются первыми, включаются в итоговую стоимость больше, чем те, которые выбираются позже. Следовательно, оптимально сначала выбирать меньшие палочки, чтобы получить наименьшую стоимость.

3⃣Для выполнения следующих задач будет оптимальна структура данных min heap (которая обычно реализуется как PriorityQueue в большинстве языков): получить две самые маленькие палочки (stick1 и stick2) из массива; добавить одну палочку (stick1 + stick2) обратно в массив. Эта структура данных дает сложность O(logN) для обеих операций.

😎 Решение:
class Solution {
function connectSticks($sticks) {
$pq = new SplPriorityQueue();
foreach ($sticks as $stick) {
$pq->insert($stick, -$stick);
}

$totalCost = 0;

while ($pq->count() > 1) {
$stick1 = $pq->extract();
$stick2 = $pq->extract();
$cost = $stick1 + $stick2;
$totalCost += $cost;
$pq->insert($cost, -$cost);
}

return $totalCost;
}
}


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

Дан массив чисел nums. Верните количество чисел в массиве, которые содержат четное количество цифр.

Пример:
Input: nums = [12,345,2,6,7896]
Output: 2
Explanation:
12 contains 2 digits (even number of digits).
345 contains 3 digits (odd number of digits).
2 contains 1 digit (odd number of digits).
6 contains 1 digit (odd number of digits).
7896 contains 4 digits (even number of digits).
Therefore only 12 and 7896 contain an even number of digits.


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

1⃣Определите вспомогательную функцию hasEvenDigits, которая принимает num в качестве входных данных и возвращает true, если количество цифр четное, иначе возвращает false.

2⃣Внутри функции hasEvenDigits. Инициализируйте переменную digitCount значением 0. Пока num не равно нулю: Увеличивайте digitCount на 1. Делите num на 10. Возвращайте digitCount & 1 == 0.

3⃣В функции findNumbers. Инициализируйте переменную evenDigitCount значением 0. Для каждого числа num в массиве nums, проверяйте, возвращает ли hasEvenDigits(num) значение true. Если да, увеличивайте evenDigitCount на 1. Возвращайте evenDigitCount.

😎 Решение:
class Solution {
private function hasEvenDigits($num) {
$digitCount = 0;
while ($num > 0) {
$digitCount++;
$num = intdiv($num, 10);
}
return ($digitCount & 1) == 0;
}

public function findNumbers($nums) {
$evenDigitCount = 0;
foreach ($nums as $num) {
if ($this->hasEvenDigits($num)) {
$evenDigitCount++;
}
}
return $evenDigitCount;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 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⃣Возвращение результата:
Верните абсолютное значение разницы в днях для получения положительного числа.

😎 Решение:
class Solution {
function daysBetweenDates($date1, $date2) {
$d1 = new DateTime($date1);
$d2 = new DateTime($date2);
return abs($d2->diff($d1)->days);
}
}


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

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

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


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

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

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

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

😎 Решение:
class Solution {
function reverseWords($s) {
$chars = str_split($s);
$lastSpaceIndex = -1;
$len = count($chars);

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

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


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from easyoffer
Официальный релиз easyoffer 2.0 состоится уже в течение нескольких дней.

Напоминаю, что в честь релиза запускаем акцию.

Первые 500 покупателей получат:

🚀 Скидку 50% на PRO тариф на 1 год
🎁 Подарок ценностью 5000₽ для тех, кто подписан на этот канал

🔔 Подпишитесь на этот канал: https://t.iss.one/+b2fZN17A9OQ3ZmJi
В нем мы опубликуем сообщение о релизе в первую очередь
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1099. Two Sum Less Than K
Сложность: easy

Дан массив целых чисел nums и целое число k. Верните максимальную сумму, такую что существуют i < j, при которых nums[i] + nums[j] = sum и sum < k. Если не существует таких i и j, удовлетворяющих этому условию, верните -1.

Пример:
Input: nums = [34,23,1,24,75,33,54,8], k = 60
Output: 58
Explanation: We can use 34 and 24 to sum 58 which is less than 60.


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

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

2⃣Установите указатели: левый на начало массива, правый на конец.

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

😎 Решение:
class Solution {
function twoSumLessThanK($nums, $k) {
$answer = -1;
$count = array_fill(0, 1001, 0);
foreach ($nums as $num) {
$count[$num]++;
}
$lo = 1;
$hi = 1000;
while ($lo <= $hi) {
if ($lo + $hi >= $k || $count[$hi] == 0) {
$hi--;
} else {
if ($count[$lo] > ($lo < $hi ? 0 : 1)) {
$answer = max($answer, $lo + $hi);
}
$lo++;
}
}
return $answer;
}
}


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

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

Пример:
Input: numerator = 1, denominator = 2
Output: "0.5"


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

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

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

3⃣Учет особенностей:
Будьте осторожны с крайними случаями, такими как отрицательные дроби или особо сложные случаи, например, деление −1 на −2147483648. В этих случаях следует корректно обрабатывать знаки и возможные переполнения.

😎 Решение:
class Solution {
function fractionToDecimal($numerator, $denominator) {
if ($numerator == 0) {
return "0";
}

$fraction = "";
if (($numerator < 0) xor ($denominator < 0)) {
$fraction .= "-";
}

$dividend = abs($numerator);
$divisor = abs($denominator);

$fraction .= intval($dividend / $divisor);
$remainder = $dividend % $divisor;
if ($remainder == 0) {
return $fraction;
}

$fraction .= ".";
$lookup = [];
while ($remainder != 0) {
if (isset($lookup[$remainder])) {
$pos = $lookup[$remainder];
$fraction = substr($fraction, 0, $pos) . "(" . substr($fraction, $pos) . ")";
break;
}
$lookup[$remainder] = strlen($fraction);
$remainder *= 10;
$fraction .= intval($remainder / $divisor);
$remainder %= $divisor;
}

return $fraction;
}
}


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

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

Пример:
Input: root = [1,null,3,2,4,null,null,null,5]
Output: 3
Explanation: Longest consecutive sequence path is 3-4-5, so return 3.


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

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

2⃣Сравнение текущего узла с родительским узлом:
Для каждого узла сравните его значение со значением родительского узла.
Если значение текущего узла на единицу больше значения родительского узла, увеличьте length.
Если значение текущего узла не является последовательным (не больше на единицу), сбросьте length на 1.

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

😎 Решение:
class Solution {
private $maxLength = 0;

public function longestConsecutive($root) {
$this->dfs($root, null, 0);
return $this->maxLength;
}

private function dfs($node, $parent, $length) {
if ($node === null) return;
if ($parent !== null && $node->val === $parent->val + 1) {
$length++;
} else {
$length = 1;
}
$this->maxLength = max($this->maxLength, $length);
$this->dfs($node->left, $node, $length);
$this->dfs($node->right, $node, $length);
}
}
?>


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

Если задан массив целых чисел n x n, верните минимальную сумму любого падающего пути через матрицу. Падающий путь начинается с любого элемента в первой строке и выбирает элемент в следующей строке, который находится либо прямо под ним, либо по диагонали слева/справа. В частности, следующим элементом из позиции (row, col) будет (row + 1, col - 1), (row + 1, col) или (row + 1, col + 1).

Пример:
Input: matrix = [[2,1,3],[6,5,4],[7,8,9]]
Output: 13


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

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

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

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

😎 Решение:
function minFallingPathSum($matrix) {
$n = count($matrix);
$dp = $matrix[0];

for ($i = 1; $i < $n; $i++) {
$newDp = array_fill(0, $n, 0);
for ($j = 0; $j < $n; $j++) {
$newDp[$j] = $matrix[$i][$j] + min($dp[$j], $j > 0 ? $dp[$j - 1] : PHP_INT_MAX, $j < $n - 1 ? $dp[$j + 1] : PHP_INT_MAX);
}
$dp = $newDp;
}

return min($dp);
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix
Сложность: hard

Дана бинарная матрица mat размером m x n. За один шаг вы можете выбрать одну ячейку и перевернуть её и всех её четырех соседей, если они существуют (Перевернуть означает изменить 1 на 0 и 0 на 1). Пара ячеек называется соседями, если они имеют общую границу.

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

Бинарная матрица - это матрица, в которой все ячейки равны 0 или 1.
Нулевая матрица - это матрица, в которой все ячейки равны 0.

Пример:
Input: mat = [[0,0],[0,1]]
Output: 3
Explanation: One possible solution is to flip (1, 0) then (0, 1) and finally (1, 1) as shown.


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

1⃣Переберите все возможные варианты решений для первой строки матрицы. Каждое решение представляется массивом, где каждый элемент равен 0 или 1, указывая, перевернут ли соответствующий элемент в первой строке. Инициализируйте два бинарных массива для каждой строки: lastState[], содержащий значения предыдущей строки, и changed[], представляющий, были ли значения в текущей строке перевернуты при работе с предыдущей строкой.

2⃣Для каждой строки в матрице используйте следующий шаг для вычисления состояния, инициализированного как changed:
Для каждой позиции j в диапазоне [0, n - 1] текущей строки измените значение state[j] соответственно, если lastState[j] равно 1. Переверните state[j], state[j - 1] и state[j + 1], если они существуют. Увеличьте счетчик переворотов на 1.
Значения, которые будут перевернуты в следующей строке, точно равны lastState, а решение для следующей строки точно равно массиву state. Поэтому установите changed = lastState и lastState = state, затем переходите к следующей строке.

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

😎 Решение:
class Solution {
private function better($x, $y) {
return $x < 0 || ($y >= 0 && $y < $x) ? $y : $x;
}

private function dfs($mat, &$operations) {
if (count($operations) == count($mat[0])) {
$changed = array_fill(0, count($mat[0]), 0);
$lastState = $operations;
$maybe = 0;
foreach ($mat as $row) {
$state = $changed;
foreach ($row as $j => $cell) {
$state[$j] ^= $cell;
if ($lastState[$j]) {
$state[$j] ^= 1;
if ($j > 0) {
$state[$j - 1] ^= 1;
}
if ($j + 1 < count($row)) {
$state[$j + 1] ^= 1;
}
$maybe++;
}
}
$changed = $lastState;
$lastState = $state;
}
foreach ($lastState as $x) {
if ($x) {
return -1;
}
}
return $maybe;
}
$operations[] = 0;
$maybe1 = $this->dfs($mat, $operations);
$operations[count($operations) - 1] = 1;
$maybe2 = $this->dfs($mat, $operations);
array_pop($operations);
return $this->better($maybe1, $maybe2);
}

public function minFlips($mat) {
$operations = [];
return $this->dfs($mat, $operations);
}
}


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

Например, "", "()", "(" + A + ")" или A + B, где A и B - допустимые строки со скобками, а + означает объединение строк. Все допустимые строки со скобками - "", "()", "(())()" и "(()(())".
Допустимая строка со скобками s является примитивной, если она непустая и не существует способа разбить ее на s = A + B, причем A и B - непустые допустимые строки со скобками. Если дана допустимая строка со скобками s, рассмотрим ее примитивное разложение: s = P1 + P2 + ... + Pk, где Pi - примитивные допустимые строки со скобками. Верните s после удаления крайних скобок из каждой примитивной строки в примитивном разложении s.

Пример:
Input: s = "(()())(())"
Output: "()()()"


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

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

2⃣Обработка строки:
Итерируйте по каждому символу строки.
Если встречаете (, увеличивайте счетчик уровня вложенности. Если уровень вложенности больше 1, добавьте ( в результат.
Если встречаете ), уменьшайте счетчик уровня вложенности. Если уровень вложенности больше 0 перед уменьшением, добавьте ) в результат.

3⃣Возврат результата:
Верните результат, содержащий строку без крайних скобок из каждой примитивной строки.

😎 Решение:
class Solution {
function removeOuterParentheses($s) {
$result = '';
$level = 0;

for ($i = 0; $i < strlen($s); $i++) {
if ($s[$i] == '(') {
if ($level > 0) {
$result .= $s[$i];
}
$level++;
} else {
$level--;
if ($level > 0) {
$result .= $s[$i];
}
}
}

return $result;
}
}


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