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

Тесты t.me/+pSDoLEZBQRZlNmFi
Вопросы собесов t.me/+RJaDhjYaQDo2Njcy
Вакансии t.me/+J-DKRUtjUgMxZGNi
Download Telegram
Задача: 1015. Smallest Integer Divisible by K
Сложность: medium

Задано целое положительное число k, необходимо найти длину наименьшего целого положительного числа n, такого, что n делится на k, и n содержит только цифру 1. Верните длину n. Если такого n не существует, верните -1. Примечание: n может не поместиться в 64-битное знаковое целое число.

Пример:
Input: k = 1
Output: 1


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

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

2⃣Итеративное нахождение числа:
Используйте цикл, чтобы умножать num на 10 и добавлять 1 в каждой итерации, и каждый раз вычисляйте остаток от деления num на k.
Увеличивайте length на 1 в каждой итерации.
Если в какой-то итерации num % k == 0, верните length.

3⃣Проверка бесконечного цикла:
Если цикл длится слишком долго (например, 10^6 итераций), верните -1, чтобы предотвратить бесконечный цикл для случаев, когда решение не существует.

😎 Решение:
class Solution {
function smallestRepunitDivByK($k) {
$num = 1;
$length = 1;
$seen = [];

while ($num % $k != 0) {
if (in_array($num % $k, $seen)) {
return -1;
}
$seen[] = $num % $k;
$num = ($num * 10 + 1) % $k;
$length++;
}

return $length;
}
}


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

Сообщение, содержащее буквы от A до Z, можно закодировать в числа с использованием следующего соответствия:

- 'A' -> "1"
- 'B' -> "2"
- ...
- 'Z' -> "26"

Для декодирования закодированного сообщения все цифры должны быть сгруппированы и затем отображены обратно в буквы с использованием обратного соответствия (существует несколько способов). Например, "11106" можно представить как:

- "AAJF" с группировкой (1 1 10 6)
- "KJF" с группировкой (11 10 6)

Обратите внимание, что группировка (1 11 06) недопустима, потому что "06" не может быть преобразовано в 'F', так как "6" отличается от "06".

Для данной строки s, содержащей только цифры, верните количество способов декодирования.

Тестовые случаи сформированы таким образом, что ответ укладывается в 32-битное целое число.

Пример:
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).


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

1⃣Входим в рекурсию с данной строкой, начиная с индекса 0.

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

3⃣Мемоизация помогает снизить сложность, которая иначе была бы экспоненциальной. Мы проверяем словарь memo, чтобы увидеть, существует ли уже результат для данной подстроки. Если результат уже находится в memo, мы возвращаем этот результат. В противном случае количество способов для данной строки определяется путем рекурсивного вызова функции с индексом +1 для следующей подстроки и индексом +2 после проверки на валидность двузначного декодирования. Результат также сохраняется в memo с ключом как текущий индекс, чтобы сохранить его для будущих пересекающихся подзадач.

😎 Решение:
class Solution {
private function valid($s, $start, $length) {
if ($length == 1) {
return true;
}
if ($s[$start] == '0') {
return false;
}
if ($length > 3) {
return false;
}
$num = substr($s, $start, $length);
return (int)$num <= 255;
}

private function helper($s, $startIndex, &$dots, &$ans) {
$remainingLength = strlen($s) - $startIndex;
$remainingNumberOfIntegers = 4 - count($dots);
if ($remainingLength > $remainingNumberOfIntegers * 3 || $remainingLength < $remainingNumberOfIntegers) {
return;
}
if (count($dots) == 3) {
if ($this->valid($s, $startIndex, $remainingLength)) {
$temp = "";
$last = 0;
foreach ($dots as $dot) {
$temp .= substr($s, $last, $dot) . ".";
$last += $dot;
}
$temp .= substr($s, $startIndex);
$ans[] = $temp;
}
return;
}
for ($curPos = 1; $curPos <= min(3, $remainingLength); $curPos++) {
$dots[] = $curPos;
if ($this->valid($s, $startIndex, $curPos)) {
$this->helper($s, $startIndex + $curPos, $dots, $ans);
}
array_pop($dots);
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 211. Design Add and Search Words Data Structure
Сложность: medium

Спроектируйте структуру данных, которая поддерживает добавление новых слов и проверку, соответствует ли строка любому ранее добавленному слову.
Реализуйте класс WordDictionary:
WordDictionary() инициализирует объект.
void addWord(word) добавляет слово в структуру данных, оно может быть сопоставлено позже.
bool search(word) возвращает true, если в структуре данных есть строка, которая соответствует слову, или false в противном случае. Слово может содержать точки '.', где точки могут быть сопоставлены с любой буквой.

Пример:
Input
["WordDictionary","addWord","addWord","addWord","search","search","search","search"]
[[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]]
Output
[null,null,null,null,false,true,true,true]

Explanation
WordDictionary wordDictionary = new WordDictionary();
wordDictionary.addWord("bad");
wordDictionary.addWord("dad");
wordDictionary.addWord("mad");
wordDictionary.search("pad"); // return False
wordDictionary.search("bad"); // return True
wordDictionary.search(".ad"); // return True
wordDictionary.search("b.."); // return True


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

1⃣Инициализация и добавление слова:
Создайте класс WordDictionary с конструктором, который инициализирует корневой узел TrieNode.
Метод addWord(String word) добавляет слово в структуру данных. Инициализируйте текущий узел как корневой и пройдите по каждому символу слова. Если символ отсутствует среди дочерних узлов текущего узла, создайте новый узел. Перемещайтесь к следующему узлу. В конце отметьте текущий узел как конец слова.

2⃣Поиск слова в узле:
Метод searchInNode(String word, TrieNode node) ищет слово в переданном узле TrieNode. Пройдите по каждому символу слова. Если символ не найден среди дочерних узлов текущего узла, проверьте, является ли символ точкой '.'. Если да, рекурсивно выполните поиск в каждом дочернем узле текущего узла. Если символ не точка и не найден, верните false. Если символ найден, перейдите к следующему узлу. В конце проверьте, является ли текущий узел концом слова.

3⃣Поиск слова в структуре данных:
Метод search(String word) использует метод searchInNode() для поиска слова, начиная с корневого узла. Верните результат поиска. Если слово найдено, верните true, иначе false.

😎 Решение:
class TrieNode {
public $children;
public $isWord;

public function __construct() {
$this->children = [];
$this->isWord = false;
}
}

class WordDictionary {
private $root;

public function __construct() {
$this->root = new TrieNode();
}

public function addWord($word) {
$node = $this->root;
for ($i = 0; $i < strlen($word); $i++) {
$ch = $word[$i];
if (!isset($node->children[$ch])) {
$node->children[$ch] = new TrieNode();
}
$node = $node->children[$ch];
}
$node->isWord = true;
}

private function searchInNode($word, $node) {
for ($i = 0; $i < strlen($word); $i++) {
$ch = $word[$i];
if (!isset($node->children[$ch])) {
if ($ch === '.') {
foreach ($node->children as $child) {
if ($this->searchInNode(substr($word, $i + 1), $child)) {
return true;
}
}
}
return false;
} else {
$node = $node->children[$ch];
}
}
return $node->isWord;
}

public function search($word) {
return $this->searchInNode($word, $this->root);
}
}


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

Десятичное число можно преобразовать в его шестнадцатеричное представление, сначала преобразовав его в прописную шестнадцатеричную строку, а затем заменив все вхождения цифры '0' на букву 'O', а цифры '1' - на букву 'I'. Такое представление допустимо тогда и только тогда, когда оно состоит только из букв набора {'A', 'B', 'C', 'D', 'E', 'F', 'I', 'O'}. Получив строку num, представляющую десятичное целое число n, верните шестнадцатеричное представление n, если оно допустимо, иначе верните "ERROR".

Пример:
Input: num = "257"
Output: "IOI"


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

1⃣Преобразуйте десятичное число в шестнадцатеричную строку в верхнем регистре.

2⃣Замените все вхождения цифры '0' на букву 'O', а цифры '1' на букву 'I'

3⃣Проверьте, что преобразованная строка содержит только допустимые символы. Если это так, верните строку, иначе верните "ERROR".

😎 Решение:
function toHexString($num) {
$hexStr = strtoupper(dechex($num));
$hexStr = str_replace(['0', '1'], ['O', 'I'], $hexStr);
foreach (str_split($hexStr) as $char) {
if (!in_array($char, str_split('ABCDEFIO'))) {
return "ERROR";
}
}
return $hexStr;
}


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

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

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


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

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

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

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

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

function flipEquiv($root1, $root2) {
if ($root1 == null && $root2 == null) return true;
if ($root1 == null || $root2 == null) return false;
if ($root1->val != $root2->val) return false;

return (flipEquiv($root1->left, $root2->left) && flipEquiv($root1->right, $root2->right)) ||
(flipEquiv($root1->left, $root2->right) && flipEquiv($root1->right, $root2->left));
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Когда проекты растут, а требований становится больше, скорость разработки начинает упираться не в язык или фреймворки, а в процессы, инструменты и организацию работы.

С 1 по 5 декабря конференция Podlodka PHP Crew собирает сезон о том, как разгонять PHP-разработку без стресса и перегрузов.

📌 В программу вошли новые доклады:

🧩 Тесты для ускорения — Александр Макаров (Twindo): о роли тестирования в скорости разработки, какие виды тестов действительно дают ускорение, и как распределить ответственность между разработчиками, QA и LLM.

📄 Контракты пишем — код генерим — Александр Забанов (Вебпрактик): contract-first подход, который снижает количество ошибок и делает интеграции предсказуемыми.

🧱 Платформа как LEGO — Антон Комарев (BelkaCar): как собрать внутреннюю платформу для разработчиков из готовых «кубиков» и убрать хаос внутренних тулов.

🎛 Фича-флаги — Сергей Волошин (Вебпрактик): как перейти от «деплой = релиз» к гибкому управлению функциональностью и выпускать код хоть каждый час.

💡Все темы прикладные, с упором на ускорение команд и уменьшение рутины.

🔗 Программа и билеты: https://podlodka.io/phpcrew
Когда проекты растут, а требований становится больше, скорость разработки начинает упираться не в язык или фреймворки, а в процессы, инструменты и организацию работы.

С 1 по 5 декабря конференция Podlodka PHP Crew собирает сезон о том, как разгонять PHP-разработку без стресса и перегрузов.

📌 В программу вошли новые доклады:

🧩 Тесты для ускорения — Александр Макаров (Twindo): о роли тестирования в скорости разработки, какие виды тестов действительно дают ускорение, и как распределить ответственность между разработчиками, QA и LLM.

📄 Контракты пишем — код генерим — Александр Забанов (Вебпрактик): contract-first подход, который снижает количество ошибок и делает интеграции предсказуемыми.

🧱 Платформа как LEGO — Антон Комарев (BelkaCar): как собрать внутреннюю платформу для разработчиков из готовых «кубиков» и убрать хаос внутренних тулов.

🎛 Фича-флаги — Сергей Волошин (Вебпрактик): как перейти от «деплой = релиз» к гибкому управлению функциональностью и выпускать код хоть каждый час.

💡Все темы прикладные, с упором на ускорение команд и уменьшение рутины.

🔗 Программа и билеты: https://podlodka.io/phpcrew
Задача: 1518. Water Bottles
Сложность: easy

У вас есть numBottles полных бутылок воды. За каждые numExchange пустых бутылок можно получить одну полную. Посчитайте, сколько всего бутылок воды можно выпить, если каждый раз менять пустые на новые.

Пример:
Input: numBottles = 9, numExchange = 3
Output: 13
Explanation: You can exchange 3 empty bottles to get 1 full water bottle.
Number of water bottles you can drink: 9 + 3 + 1 = 13.


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

1⃣Инициализируйте переменную ответа consumedBottles значением 0.

2⃣Продолжайте выполнять следующие действия, пока количество numBottles больше или равно numExchange: Выпейте numExchange количество полных бутылок, т.е. добавьте numExchange к consumedBottles. Уменьшите numExchange от доступных полных бутылок numBottles. Обменяйте пустые бутылки на одну полную бутылку, т.е. увеличьте numBottles на одну.

3⃣Верните consumedBottles + numBottles.

😎 Решение:
class Solution {
function numWaterBottles($numBottles, $numExchange) {
$consumedBottles = 0;

while ($numBottles >= $numExchange) {
$consumedBottles += $numExchange;
$numBottles -= $numExchange;
$numBottles++;
}

return $consumedBottles + $numBottles;
}
}


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

Для кодирования последовательности целых чисел мы можем использовать кодирование по длине строки (т. е. RLE). В кодированном по длине пробега массиве четной длины (с индексацией 0) для всех четных i значение encoding[i] говорит нам о том, сколько раз неотрицательное целое значение encoding[i + 1] повторяется в последовательности.

Например, последовательность arr = [8,8,8,5,5] может быть закодирована как encoding = [3,8,2,5]. encoding = [3,8,0,9,2,5] и encoding = [2,8,1,8,2,5] также являются допустимыми RLE для arr.
Задав кодированный по длине пробега массив, разработайте итератор для его итерации. Реализуйте класс RLEIterator: RLEIterator(int[] encoded) Инициализирует объект с кодированным массивом encoded. int next(int n) Исчерпывает следующие n элементов и возвращает последний исчерпанный таким образом элемент. Если не осталось элементов для исчерпания, возвращает -1.

Пример:
Input
["RLEIterator", "next", "next", "next", "next"]
[[[3, 8, 0, 9, 2, 5]], [2], [1], [1], [2]]
Output
[null, 8, 8, 5, -1]


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

1⃣Инициализировать итератор с закодированным массивом и индексом, указывающим на текущую позицию.

2⃣При вызове метода next(n), уменьшить текущий счетчик на n или перейти к следующему числу, если текущий счетчик равен нулю.

3⃣Возвращать текущий элемент или -1, если все элементы исчерпаны.

😎 Решение:
class RLEIterator {
private $encoding;
private $index;

function __construct($encoding) {
$this->encoding = $encoding;
$this->index = 0;
}

function next($n) {
while ($this->index < count($this->encoding)) {
if ($n > $this->encoding[$this->index]) {
$n -= $this->encoding[$this->index];
$this->index += 2;
} else {
$this->encoding[$this->index] -= $n;
return $this->encoding[$this->index + 1];
}
}
return -1;
}
}


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

Имеется прямоугольный остров размером m x n, который граничит с Тихим и Атлантическим океанами. Тихий океан касается левого и верхнего краев острова, а Атлантический океан - правого и нижнего краев. Остров разбит на сетку квадратных ячеек. Вам дана целочисленная матрица heights размером m x n, где heights[r][c] - высота над уровнем моря клетки с координатами (r, c). На острове выпадает много осадков, и дождевая вода может стекать в соседние клетки прямо на север, юг, восток и запад, если высота соседней клетки меньше или равна высоте текущей клетки. Вода может течь из любой клетки, прилегающей к океану, в океан. Верните двумерный список координат сетки result, где result[i] = [ri, ci] означает, что дождевая вода может течь из клетки (ri, ci) как в Тихий, так и в Атлантический океаны.

Пример:
Input: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
Output: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]


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

1⃣Определите две матрицы для отслеживания клеток, из которых вода может течь в Тихий и Атлантический океаны, используя поиск в глубину (DFS) или поиск в ширину (BFS), начиная с границ, примыкающих к каждому океану.

2⃣Выполните поиск для каждого океана, обновляя матрицы достижимости.

3⃣Соберите координаты клеток, которые могут стекать в оба океана, проверяя пересечение двух матриц достижимости.

😎 Решение:
function pacificAtlantic($heights) {
$m = count($heights);
$n = count($heights[0]);
$pacific = array_fill(0, $m, array_fill(0, $n, false));
$atlantic = array_fill(0, $m, array_fill(0, $n, false));
$directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];

function dfs($r, $c, &$ocean, $heights, $directions) {
$ocean[$r][$c] = true;
foreach ($directions as [$dr, $dc]) {
$nr = $r + $dr;
$nc = $c + $dc;
if ($nr >= 0 && $nc >= 0 && $nr < count($heights) && $nc < count($heights[0]) && !$ocean[$nr][$nc] && $heights[$nr][$nc] >= $heights[$r][$c]) {
dfs($nr, $nc, $ocean, $heights, $directions);
}
}
}

for ($i = 0; $i < $m; $i++) {
dfs($i, 0, $pacific, $heights, $directions);
dfs($i, $n - 1, $atlantic, $heights, $directions);
}
for ($j = 0; $j < $n; $j++) {
dfs(0, $j, $pacific, $heights, $directions);
dfs($m - 1, $j, $atlantic, $heights, $directions);
}

$result = [];
for ($i = 0; $i < $m; $i++) {
for ($j = 0; $j < $n; $j++) {
if ($pacific[$i][$j] && $atlantic[$i][$j]) {
$result[] = [$i, $j];
}
}
}
return $result;
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1240. Tiling a Rectangle with the Fewest Squares
Сложность: hard

Если задан прямоугольник размером n x m, верните минимальное количество квадратов с целочисленными сторонами, которые покрывают этот прямоугольник.

Пример:
Input: n = 2, m = 3
Output: 3


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

1⃣Инициализация рекурсивной функции:
Функция принимает размеры прямоугольника n x m.

2⃣Базовый случай:
Если n = 0 или m = 0, возвращаем 0, так как не осталось пространства для покрытия.

3⃣Рекурсивный случай:
Находим наибольший возможный квадрат, который может быть размещен в текущем прямоугольнике. Это квадрат со стороной min(n, m).
Размещаем этот квадрат в левом верхнем углу и рекурсивно покрываем оставшиеся три части:
Прямоугольник слева от квадрата.
Прямоугольник сверху от квадрата.
Прямоугольник справа и снизу от квадрата.

😎 Решение:
function tilingRectangle($n, $m) {
$dp = array_fill(0, $n + 1, array_fill(0, $m + 1, PHP_INT_MAX));

for ($i = 1; $i <= min($n, $m); $i++) {
$dp[$i][$i] = 1;
}

for ($h = 1; $h <= $n; $h++) {
for ($w = 1; $w <= $m; $w++) {
if ($h == $w) continue;
for ($i = 1; $i <= intdiv($h, 2); $i++) {
$dp[$h][$w] = min($dp[$h][$w], $dp[$i][$w] + $dp[$h - $i][$w]);
}
for ($j = 1; $j <= intdiv($w, 2); $j++) {
$dp[$h][$w] = min($dp[$h][$w], $dp[$h][$j] + $dp[$h][$w - $j]);
}
}
}
return $dp[$n][$m];
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Задача: 895. Maximum Frequency Stack
Сложность: hard

Разработайте структуру данных, похожую на стек, чтобы заталкивать элементы в стек и вытаскивать из него самый частый элемент. Реализуйте класс FreqStack: FreqStack() строит пустой стек частот. void push(int val) заталкивает целое число val на вершину стека. int pop() удаляет и возвращает самый частый элемент в стеке. Если есть равенство в выборе самого частого элемента, то удаляется и возвращается элемент, который ближе всего к вершине стека.

Пример:
Input
["FreqStack", "push", "push", "push", "push", "push", "push", "pop", "pop", "pop", "pop"]
[[], [5], [7], [5], [7], [4], [5], [], [], [], []]
Output
[null, null, null, null, null, null, null, 5, 7, 5, 4]


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

1⃣Создать два словаря: freq для хранения частоты каждого элемента и group для хранения стека элементов для каждой частоты.

2⃣При добавлении элемента увеличивать его частоту в freq и добавлять его в стек соответствующей частоты в group.

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

😎 Решение:
class FreqStack {
private $freq;
private $group;
private $maxfreq;

function __construct() {
$this->freq = [];
$this->group = [];
$this->maxfreq = 0;
}

function push($val) {
$f = ($this->freq[$val] ?? 0) + 1;
$this->freq[$val] = $f;
if ($f > $this->maxfreq) {
$this->maxfreq = $f;
$this->group[$f] = [];
}
$this->group[$f][] = $val;
}

function pop() {
$val = array_pop($this->group[$this->maxfreq]);
$this->freq[$val]--;
if (empty($this->group[$this->maxfreq])) {
$this->maxfreq--;
}
return $val;
}
}


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

Дана матрица размером m×n, состоящая из целых чисел. Если элемент матрицы равен 0, установите в 0 все элементы его строки и столбца.

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

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


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

1⃣Мы перебираем матрицу и отмечаем первую ячейку строки i и первую ячейку столбца j, если условие в приведенном выше псевдокоде выполняется, т.е. если cell[i][j] == 0.

2⃣Первая ячейка строки и столбца для первой строки и первого столбца совпадают, т.е. cell[0][0]. Поэтому мы используем дополнительную переменную, чтобы узнать, был ли отмечен первый столбец, а cell[0][0] используется для того же для первой строки.

3⃣Теперь мы перебираем исходную матрицу, начиная со второй строки и второго столбца, т.е. с matrix[1][1]. Для каждой ячейки мы проверяем, были ли ранее отмечены строка r или столбец c, проверяя соответствующую первую ячейку строки или первую ячейку столбца. Если любая из них была отмечена, мы устанавливаем значение в ячейке на 0. Обратите внимание, что первая строка и первый столбец служат как row_set и column_set, которые мы использовали в первом подходе. Затем мы проверяем, равна ли cell[0][0] нулю, если это так, мы отмечаем первую строку как ноль. И, наконец, если первый столбец был отмечен, мы делаем все записи в нем нулевыми.

😎 Решение:
function setZeroes(&$matrix) {
$isCol = false;
$R = count($matrix);
$C = count($matrix[0]);

for ($i = 0; $i < $R; $i++) {
if ($matrix[$i][0] == 0) {
$isCol = true;
}
for ($j = 1; $j < $C; $j++) {
if ($matrix[$i][$j] == 0) {
$matrix[0][$j] = 0;
$matrix[$i][0] = 0;
}
}
}

for ($i = 1; $i < $R; $i++) {
for ($j = 1; $j < $C; $j++) {
if ($matrix[$i][0] == 0 || $matrix[0][$j] == 0) {
$matrix[$i][$j] = 0;
}
}
}

if ($matrix[0][0] == 0) {
for ($j = 0; $j < $C; $j++) {
$matrix[0][$j] = 0;
}
}

if ($isCol) {
for ($i = 0; $i < $R; $i++) {
$matrix[$i][0] = 0;
}
}
}


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

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

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


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

1⃣Если длина curr равна длине nums, добавьте копию curr в ans и вернитесь.

2⃣Итерируйтесь по nums. Для каждого num, если num не в curr, выполните следующее:
Добавьте num в curr и вызовите backtrack(curr), затем удалите num из curr.

3⃣Вызовите backtrack с изначально пустым curr.
Верните ans.

😎 Решение:
function permute($nums) {
$ans = [];
$backtrack = function (&$curr) use (&$ans, &$backtrack, $nums) {
if (count($curr) === count($nums)) {
$ans[] = $curr;
return;
}
foreach ($nums as $num) {
if (!in_array($num, $curr)) {
$curr[] = $num;
$backtrack($curr);
array_pop($curr);
}
}
};
$backtrack([]);
return $ans;
}


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

Вы играете в игру "Быки и коровы" со своим другом.
Вы записываете секретное число и просите своего друга угадать, что это за число. Когда ваш друг делает предположение, вы даете ему подсказку со следующей информацией:
Количество "быков", то есть цифры в предположении, которые находятся на правильной позиции.
Количество "коров", то есть цифры в предположении, которые есть в вашем секретном числе, но находятся на неправильной позиции. Конкретно, это не-бычьи цифры в предположении, которые можно переставить так, чтобы они стали быками.
Дано секретное число secret и предположение вашего друга guess, верните подсказку для предположения вашего друга.
Подсказка должна быть в формате "xAyB", где x — количество быков, а y — количество коров. Обратите внимание, что и secret, и guess могут содержать повторяющиеся цифры.

Пример:
Input: secret = "1807", guess = "7810"
Output: "1A3B"
Explanation: Bulls are connected with a '|' and cows are underlined:
"1807"
|
"7810"


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

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

2⃣Обход строки guess:
Для каждого символа ch в строке guess:
Если ch присутствует в строке secret:
Если текущий символ ch совпадает с символом на той же позиции в secret (ch == secret[idx]):
Увеличьте количество быков: bulls += 1.
Обновите количество коров, если количество текущего символа в хеш-таблице отрицательное или равно нулю (то есть этот символ уже использовался для коров): cows -= int(h[ch] <= 0).
Если текущий символ ch не совпадает с символом на той же позиции в secret (ch != secret[idx]):
Увеличьте количество коров, если количество текущего символа в хеш-таблице больше нуля: cows += int(h[ch] > 0).
Обновите хеш-таблицу, помечая текущий символ как использованный: h[ch] -= 1.

3⃣Возврат результата:
Верните количество быков и коров в формате "xAyB".

😎 Решение:
class Solution {
function getHint($secret, $guess) {
$h = [];
for ($i = 0; $i < strlen($secret); $i++) {
$ch = $secret[$i];
if (!isset($h[$ch])) {
$h[$ch] = 0;
}
$h[$ch]++;
}

$bulls = 0;
$cows = 0;
$n = strlen($guess);
$secretArray = str_split($secret);
$guessArray = str_split($guess);

for ($idx = 0; $idx < $n; $idx++) {
$ch = $guessArray[$idx];
if (isset($h[$ch])) {
if ($ch == $secretArray[$idx]) {
$bulls++;
if ($h[$ch] <= 0) {
$cows--;
}
} else {
if ($h[$ch] > 0) {
$cows++;
}
}
$h[$ch]--;
}
}

return "{$bulls}A{$cows}B";
}
}
?>


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

Дана голова связного списка. Верните узел, с которого начинается цикл. Если цикла нет, верните null.
Цикл в связном списке существует, если есть такой узел в списке, до которого можно добраться снова, последовательно следуя по указателю next. Внутренне переменная pos используется для обозначения индекса узла, к которому подключен указатель next последнего узла (индексация с нуля). Она равна -1, если цикла нет. Обратите внимание, что pos не передается в качестве параметра.
Не модифицируйте связный список.

Пример:
Input: head = [3,2,0,-4], pos = 1
Output: tail connects to node index 1
Explanation: There is a cycle in the linked list, where tail connects to the second node.


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

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

2⃣Проверка на наличие узла в множестве:
Для каждого посещенного узла проверьте, содержится ли он уже в множестве nodes_seen.
Если узел найден в множестве, это означает, что был найден цикл. Верните текущий узел как точку входа в цикл.

3⃣Добавление узла в множество или завершение обхода:
Если узел не найден в nodes_seen, добавьте его в множество и перейдите к следующему узлу.
Если узел становится равным null (конец списка), верните null. В списке нет цикла, так как в случае наличия цикла вы бы застряли в петле и не достигли бы конца списка.

😎 Решение:
class ListNode {
public $val;
public $next;

public function __construct($val = 0, $next = null) {
$this->val = $val;
$this->next = $next;
}
}

function detectCycle($head) {
$nodesSeen = [];
$node = $head;
while ($node !== null) {
if (in_array($node, $nodesSeen, true)) {
return $node;
} else {
$nodesSeen[] = $node;
$node = $node->next;
}
}
return null;
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1180. Count Substrings with Only One Distinct Letter
Сложность: easy

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

Пример:
Input: s = "aaaba"
Output: 8
Explanation: The substrings with one distinct letter are "aaa", "aa", "a", "b".
"aaa" occurs 1 time.
"aa" occurs 2 times.
"a" occurs 4 times.
"b" occurs 1 time.
So the answer is 1 + 2 + 4 + 1 = 8.


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

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

2⃣Итерируйте по строке S: Если мы не достигли конца и новый символ S[right] такой же, как и начальный символ S[left], увеличьте right на 1 для дальнейшего исследования строки S; в противном случае вычислите длину подстроки как right - left и примените формулу суммы арифметической последовательности; не забудьте установить right в left для начала исследования новой подстроки.

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

😎 Решение:
class Solution {
function countLetters($S) {
$total = 0;
$left = 0;

for ($right = 0; $right <= strlen($S); $right++) {
if ($right == strlen($S) || $S[$left] != $S[$right]) {
$lenSubstring = $right - $left;
$total += (1 + $lenSubstring) * $lenSubstring / 2;
$left = $right;
}
}
return $total;
}
}


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

Даны две строки a и b. Верните минимальное количество повторений строки a, чтобы строка b стала её подстрокой. Если сделать b подстрокой a невозможно, верните -1.

Обратите внимание: строка "abc", повторенная 0 раз, это "", повторенная 1 раз - "abc", повторенная 2 раза - "abcabc".

Пример:
Input: a = "abcd", b = "cdabcdab"
Output: 3
Explanation: We return 3 because by repeating a three times "abcdabcdabcd", b is a substring of it.


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

1⃣Найти минимальное количество повторений строки A, чтобы её длина стала больше или равна длине B. Это значение q = ceil(len(B) / len(A)).

2⃣Проверить, является ли B подстрокой строки A, повторенной q раз. Если да, вернуть q. Иначе, проверить строку A, повторенную (q+1) раз. Если B является подстрокой этой строки, вернуть q+1.

3⃣Если B не является подстрокой ни в одном из случаев, вернуть -1.

😎 Решение:
class Solution {
function repeatedStringMatch($A, $B) {
$q = 1;
$S = $A;
while (strlen($S) < strlen($B)) {
$S .= $A;
$q++;
}
if (strpos($S, $B) !== false) return $q;
if (strpos($S . $A, $B) !== false) return $q + 1;
return -1;
}
}


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

Допустимый IPv4-адрес — это IP в форме "x1.x2.x3.x4", где 0 <= xi <= 255 и xi не может содержать ведущие нули. Например, "192.168.1.1" и "192.168.1.0" являются допустимыми IPv4-адресами, тогда как "192.168.01.1", "192.168.1.00" и "192.168@1.1" являются недопустимыми IPv4-адресами.
Допустимый IPv6-адрес — это IP в форме "x1:x2:x3:x4:x5:x6:x7
", где:
1 <= xi.length <= 4
xi — это шестнадцатеричная строка, которая может содержать цифры, строчные английские буквы ('a' до 'f') и прописные английские буквы ('A' до 'F').
Ведущие нули в xi допускаются.

Пример:
Input: queryIP = "172.16.254.1"
Output: "IPv4"
Explanation: This is a valid IPv4 address, return "IPv4".


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

1⃣Для проверки адреса IPv4:
Разделить IP на четыре части по разделителю ".".
Проверить каждую подстроку:
Является ли она целым числом между 0 и 255.
Не содержит ли она ведущих нулей (исключение — число "0").

2⃣Для проверки адреса IPv6:
Разделить IP на восемь частей по разделителю ":".
Проверить каждую подстроку:
Является ли она шестнадцатеричным числом длиной от 1 до 4 символов.

3⃣Если IP не соответствует ни одному из форматов, вернуть "Neither".

😎 Решение:
class Solution {
public function validateIPv4($IP) {
$nums = explode('.', $IP);
if (count($nums) != 4) return "Neither";
foreach ($nums as $x) {
if (strlen($x) == 0 || strlen($x) > 3) return "Neither";
if ($x[0] == '0' && strlen($x) != 1) return "Neither";
if (!ctype_digit($x)) return "Neither";
if (intval($x) > 255) return "Neither";
}
return "IPv4";
}

public function validateIPv6($IP) {
$nums = explode(':', $IP);
$hexdigits = "0123456789abcdefABCDEF";
if (count($nums) != 8) return "Neither";
foreach ($nums as $x) {
if (strlen($x) == 0 || strlen($x) > 4) return "Neither";
for ($i = 0; $i < strlen($x); $i++) {
if (strpos($hexdigits, $x[$i]) === false) return "Neither";
}
}
return "IPv6";
}

public function validIPAddress($IP) {
if (substr_count($IP, '.') == 3) {
return $this->validateIPv4($IP);
} elseif (substr_count($IP, ':') == 7) {
return $this->validateIPv6($IP);
} else {
return "Neither";
}
}
}


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

Вам дан массив из n строк одинаковой длины. Мы можем выбрать любые индексы удаления и удалить все символы в этих индексах для каждой строки.

Например, если у нас есть strs = ["abcdef", "uvwxyz"] и индексы удаления {0, 2, 3}, то конечный массив после удаления будет ["bef", "vyz"]. Предположим, что мы выбрали набор индексов удаления answer таким образом, что после удаления конечный массив имеет элементы в лексикографическом порядке (т.е, strs[0] <= strs[1] <= strs[2] <= ... <= strs[n - 1]). Возвращает минимально возможное значение answer.length.

Пример:
Input: strs = ["ca","bb","ac"]
Output: 1


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

1⃣Определить количество строк n и длину каждой строки m.
Создать массив delete_count длиной m, который будет отслеживать количество удаляемых столбцов.

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

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

😎 Решение:
function minDeletionSize($strs) {
$n = count($strs);
$m = strlen($strs[0]);
$deleteCount = array_fill(0, $m, false);

function isSorted($strs, $deleteCount) {
$n = count($strs);
$m = count($deleteCount);
for ($i = 0; $i < $n - 1; $i++) {
for ($j = 0; $j < $m; $j++) {
if ($deleteCount[$j]) continue;
if ($strs[$i][$j] > $strs[$i + 1][$j]) return false;
if ($strs[$i][$j] < $strs[$i + 1][$j]) break;
}
}
return true;
}

while (!isSorted($strs, $deleteCount)) {
for ($j = 0; $j < $m; $j++) {
if ($deleteCount[$j]) continue;
for ($i = 0; $i < $n - 1; $i++) {
if ($strs[$i][$j] > $strs[$i + 1][$j]) {
$deleteCount[$j] = true;
break;
}
}
if ($deleteCount[$j]) break;
}
}

return array_sum($deleteCount);
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1347. Minimum Number of Steps to Make Two Strings Anagram
Сложность: medium

Даны две строки одинаковой длины s и t. За один шаг вы можете выбрать любой символ строки t и заменить его другим символом.

Вернуть минимальное количество шагов, чтобы сделать t анаграммой строки s.

Анаграмма строки — это строка, которая содержит те же символы в другом (или том же) порядке.

Пример:
Input: s = "bab", t = "aba"
Output: 1
Explanation: Replace the first 'a' in t with b, t = "bba" which is anagram of s.


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

1⃣Вычислить разницу частот символов в строках t и s, сохраняя результаты в массиве count.

2⃣Подсчитать количество символов, которые нужно заменить в t, добавляя в ans только положительные значения из массива count.

3⃣Вернуть ans как минимальное количество шагов для превращения t в анаграмму строки s.

😎 Решение:
class Solution {
public function minSteps($s, $t) {
$count = array_fill(0, 26, 0);

for ($i = 0; $i < strlen($s); $i++) {
$count[ord($t[$i]) - ord('a')]++;
$count[ord($s[$i]) - ord('a')]--;
}

$ans = 0;
for ($i = 0; $i < 26; $i++) {
$ans += max(0, $count[$i]);
}

return $ans;
}
}


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