PHP | LeetCode
1.51K subscribers
168 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
Задача: 740. Delete and Earn
Сложность: medium

Вам дан целочисленный массив nums. Вы хотите максимизировать количество очков, выполнив следующую операцию любое количество раз: Выберите любой элемент nums[i] и удалите его, чтобы заработать nums[i] очков. После этого вы должны удалить каждый элемент, равный nums[i] - 1, и каждый элемент, равный nums[i] + 1. Верните максимальное количество очков, которое вы можете заработать, применив вышеуказанную операцию некоторое количество раз.

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


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

1⃣Подсчитайте количество каждого числа в массиве nums.

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

3⃣Для каждого числа num в nums, учитывайте два случая: не брать число или взять число и добавить его очки.

😎 Решение:
function deleteAndEarn($nums) {
$count = array_count_values($nums);
$avoid = $using = 0;
$prev = -1;

ksort($count);
foreach ($count as $num => $freq) {
if ($num - 1 != $prev) {
$newAvoid = max($avoid, $using);
$using = $num * $freq + max($avoid, $using);
$avoid = $newAvoid;
} else {
$newAvoid = max($avoid, $using);
$using = $num * $freq + $avoid;
$avoid = $newAvoid;
}
$prev = $num;
}

return max($avoid, $using);
}


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

Мы можем перемешать строку s, чтобы получить строку t, используя следующий алгоритм:
Дано положительное целое число n. Найдите наименьшее целое число, которое имеет точно такие же цифры, как и число n, и больше самого числа n по значению. Если такого положительного целого числа не существует, верните -1.
Учтите, что возвращенное число должно помещаться в 32-битное целое число. Если существует допустимый ответ, но он не помещается в 32-битное целое число, верните -1.

Пример:
Input: n = 12
Output: 21


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

1⃣Нахождение и перестановка цифр
Преобразуйте число n в массив цифр. Найдите первую цифру, которая нарушает убывающий порядок (с конца массива). Назовем её индексом i. Найдите первую цифру, которая больше digits[i-1] (с конца массива). Назовем её индексом j. Поменяйте местами цифры на позициях i-1 и j.

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

3⃣Проверка результата и преобразование обратно в число
Преобразуйте массив цифр обратно в число. Если число превышает 32-битный предел, верните -1. В противном случае верните полученное число.

😎 Решение:
class Solution {
private function swap($s, $i0, $i1) {
if ($i0 == $i1) return $s;
$chars = str_split($s);
$temp = $chars[$i0];
$chars[$i0] = $chars[$i1];
$chars[$i1] = $temp;
return implode('', $chars);
}

private $list = [];

private function permute($a, $l, $r) {
if ($l == $r) {
$this->list[] = $a;
} else {
for ($i = $l; $i <= $r; $i++) {
$a = $this->swap($a, $l, $i);
$this->permute($a, $l + 1, $r);
$a = $this->swap($a, $l, $i);
}
}
}

public function nextGreaterElement($n) {
$s = strval($n);
$this->permute($s, 0, strlen($s) - 1);
sort($this->list);
$index = array_search($s, $this->list);
if ($index !== false && $index < count($this->list) - 1) {
$result = intval($this->list[$index + 1]);
if ($result <= 2147483647) {
return $result;
}
}
return -1;
}
}


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

Дана строка s, вернуть true, если s может быть палиндромом после удаления не более одного символа из нее.

Пример:
Input: s = "aba"
Output: true


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

1⃣Создайте вспомогательную функцию checkPalindrome, которая принимает строку s и два указателя i и j. Эта функция возвращает логическое значение, указывающее, является ли подстрока s.substring(i, j) палиндромом.

2⃣Инициализируйте два указателя: i = 0 и j = s.length() - 1. Пока i < j, проверьте, совпадают ли символы в индексах i и j. Если нет, это значит, что нам нужно удалить один из этих символов.

3⃣Попробуйте оба варианта, используя checkPalindrome. Верните true, если либо checkPalindrome(s, i, j - 1), либо checkPalindrome(s, i + 1, j) возвращает true. Если мы выходим из цикла while, это значит, что исходная строка является палиндромом. Поскольку нам не нужно было использовать удаление, следует вернуть true.

😎 Решение:
class Solution {
private function checkPalindrome($s, $i, $j) {
while ($i < $j) {
if ($s[$i] != $s[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}

public function validPalindrome($s) {
$i = 0;
$j = strlen($s) - 1;

while ($i < $j) {
if ($s[$i] != $s[$j]) {
return $this->checkPalindrome($s, $i, $j - 1) || $this->checkPalindrome($s, $i + 1, $j);
}
$i++;
$j--;
}

return true;
}
}


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

Представьте, что у вас есть специальная клавиатура со следующими клавишами: A: Напечатать одну букву "A" на экране. Ctrl-A: Выделить весь экран. Ctrl-C: Скопировать выделение в буфер. Ctrl-V: Печать буфера на экране с добавлением его после того, что уже было напечатано. Учитывая целое число n, верните максимальное количество букв 'A', которые можно напечатать на экране при нажатии не более n клавиш.

Пример:
Input: root = [1,2,3,4,null,2,4,null,null,4]
Output: [[2,4],[4]]


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

1⃣Используйте динамическое программирование для отслеживания максимального количества букв 'A' на экране после каждого числа нажатий клавиш.

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

3⃣Возвращайте значение из таблицы динамического программирования для n нажатий клавиш.

😎 Решение:
function maxA($n) {
$dp = array_fill(0, $n + 1, 0);
for ($i = 1; $i <= $n; $i++) {
$dp[$i] = $dp[$i - 1] + 1;
for ($j = 2; $j < $i; $j++) {
$dp[$i] = max($dp[$i], $dp[$j - 2] * ($i - $j + 1));
}
}
return $dp[$n];
}


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

Учитывая корневой узел двоичного дерева поиска и два целых числа low и high, верните сумму значений всех узлов со значением в диапазоне [low, high].

Пример:
Input: root = [10,5,15,3,7,null,18], low = 7, high = 15
Output: 32


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

1⃣Если дерево пустое, вернуть 0.

2⃣Если значение текущего узла меньше low, рекурсивно искать в правом поддереве.
Если значение текущего узла больше high, рекурсивно искать в левом поддереве.

3⃣Если значение текущего узла в диапазоне [low, high], включить значение узла в сумму и рекурсивно искать в обоих поддеревьях.

😎 Решение:
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 Solution {
function rangeSumBST($root, $low, $high) {
if ($root === null) return 0;
if ($root->val < $low) return $this->rangeSumBST($root->right, $low, $high);
if ($root->val > $high) return $this->rangeSumBST($root->left, $low, $high);
return $root->val + $this->rangeSumBST($root->left, $low, $high) + $this->rangeSumBST($root->right, $low, $high);
}
}


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

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

Учтите, что целые числа не должны начинаться с нулей. Целые числа, такие как 02 и 043, не допускаются.

Пример:
Input: n = 3, k = 7
Output: [181,292,707,818,929]
Explanation: Note that 070 is not a valid number, because it has leading zeroes.


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

1⃣Если n равно 1, верните массив от 0 до 9, так как все однозначные числа являются допустимыми.

2⃣Инициализируйте список очередей начальными цифрами от 1 до 9.

3⃣Для каждого уровня (от 1 до n-1) создайте новый список очередей, добавляя к каждому числу в текущей очереди допустимые цифры, которые удовлетворяют условию разницы k.

😎 Решение:
class Solution {
/**
* @param Integer $N
* @param Integer $K
* @return Integer[]
*/
function numsSameConsecDiff($N, $K) {
if ($N == 1) {
return range(0, 9);
}

$queue = range(1, 9);
for ($level = 1; $level < $N; ++$level) {
$nextQueue = [];
foreach ($queue as $num) {
$tailDigit = $num % 10;
$nextDigits = [$tailDigit + $K, $tailDigit - $K];

foreach ($nextDigits as $nextDigit) {
if ($nextDigit >= 0 && $nextDigit < 10) {
$nextQueue[] = $num * 10 + $nextDigit;
}
}
}
$queue = $nextQueue;
}

return $queue;
}
}


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

Реализуйте очередь (FIFO) с использованием только двух стеков. Реализованная очередь должна поддерживать все функции обычной очереди (push, peek, pop и empty).
Реализуйте класс MyQueue:
void push(int x) добавляет элемент x в конец очереди.
int pop() удаляет элемент из начала очереди и возвращает его.
int peek() возвращает элемент из начала очереди.
boolean empty() возвращает true, если очередь пуста, и false в противном случае.

Пример:
Input
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
Output
[null, null, null, 1, 1, false]

Explanation
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false


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

1⃣Добавление элемента: Для метода push(int x) переместите все элементы из стека s1 в стек s2. Добавьте элемент x в стек s2. Затем переместите все элементы обратно из стека s2 в стек s1. Если стек s1 пуст, обновите переменную front значением x.

2⃣Удаление и проверка первого элемента: Для метода pop() удалите элемент из начала очереди, извлекая верхний элемент из стека s1. Обновите переменную front на новый верхний элемент стека s1, если он не пуст. Для метода peek() верните значение переменной front, так как она всегда хранит первый элемент очереди.

3⃣Проверка на пустоту: Для метода empty() верните результат проверки, является ли стек s1 пустым.

😎 Решение:
class MyQueue {
private $s1 = [];
private $s2 = [];
private $front;

function push($x) {
if (empty($this->s1))
$this->front = $x;
while (!empty($this->s1))
array_push($this->s2, array_pop($this->s1));
array_push($this->s2, $x);
while (!empty($this->s2))
array_push($this->s1, array_pop($this->s2));
}

function pop() {
$res = array_pop($this->s1);
if (!empty($this->s1))
$this->front = end($this->s1);
return $res;
}

function empty() {
return empty($this->s1);
}

function peek() {
return $this->front;
}
}


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

Дан связный список длиной n, в котором каждый узел содержит дополнительный случайный указатель (random pointer), который может указывать на любой узел в списке или быть равным null.
Создайте глубокую копию списка. Глубокая копия должна состоять из ровно n совершенно новых узлов, где каждый новый узел имеет значение, равное значению соответствующего оригинального узла. Указатели next и random новых узлов должны указывать на новые узлы в скопированном списке таким образом, чтобы указатели в оригинальном и скопированном списке представляли одно и то же состояние списка. Ни один из указателей в новом списке не должен указывать на узлы в оригинальном списке.

Пример:
Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]


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

1⃣Инициализация и начало обхода:
Начните обход графа со стартового узла (head). Создайте словарь visited_dictionary для отслеживания посещенных и клонированных узлов.

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

3⃣Рекурсивные вызовы для обработки связей:
Сделайте два рекурсивных вызова для каждого узла: один используя указатель random, другой — указатель next.
Эти вызовы отражают обработку "детей" текущего узла в терминах графа, где детьми являются узлы, на которые указывают указатели random и next.

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

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

function copyRandomList($head) {
$visitedHash = [];

function cloneNode($node) use (&$visitedHash, &$cloneNode) {
if ($node === null) {
return null;
}
if (array_key_exists(spl_object_id($node), $visitedHash)) {
return $visitedHash[spl_object_id($node)];
}
$newNode = new Node($node->val);
$visitedHash[spl_object_id($node)] = $newNode;
$newNode->next = $cloneNode($node->next);
$newNode->random = $cloneNode($node->random);
return $newNode;
}

return cloneNode($head);
}


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

У вас есть n лампочек, расположенных в ряд и пронумерованных от 1 до n. Изначально все лампочки выключены. Каждый день мы включаем ровно одну лампочку, и через n дней все лампочки будут включены.

Вам дан массив bulbs длины n, где bulbs[i] = x означает, что в (i+1)-й день мы включим лампочку в позиции x, где i индексируется с 0, а x индексируется с 1.

Дано целое число k, верните минимальный номер дня, такой что существует две включенные лампочки, между которыми ровно k выключенных лампочек. Если такого дня не существует, верните -1.

Пример:
Input: bulbs = [1,3,2], k = 1
Output: 2
Explanation:
On the first day: bulbs[0] = 1, first bulb is turned on: [1,0,0]
On the second day: bulbs[1] = 3, third bulb is turned on: [1,0,1]
On the third day: bulbs[2] = 2, second bulb is turned on: [1,1,1]
We return 2 because on the second day, there were two on bulbs with one off bulb between them.


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

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

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

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

😎 Решение:
class Solution {
function kEmptySlots($bulbs, $k) {
$active = [];
$day = 0;

foreach ($bulbs as $bulb) {
$day++;
$active[] = $bulb;
sort($active);
$index = array_search($bulb, $active);

if ($index > 0 && $bulb - $active[$index - 1] - 1 == $k) {
return $day;
}
if ($index < count($active) - 1 && $active[$index + 1] - $bulb - 1 == $k) {
return $day;
}
}
return -1;
}
}


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

Есть n городов, соединенных некоторым количеством рейсов. Вам дан массив flights, где flights[i] = [fromi, toi, pricei] указывает на то, что существует рейс из города fromi в город toi с ценой pricei.

Также даны три целых числа src, dst и k. Верните самую дешевую цену от src до dst с не более чем k остановками. Если такого маршрута нет, верните -1.

Пример:
Input: n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
Output: 700
Explanation:
The graph is shown above.
The optimal path with at most 1 stop from city 0 to 3 is marked in red and has cost 100 + 600 = 700.
Note that the path through cities [0,1,2,3] is cheaper but is invalid because it uses 2 stops.


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

1⃣Создайте список смежности, где adj[X] содержит всех соседей узла X и соответствующую цену, которую нужно заплатить, чтобы перейти к соседу. Инициализируйте массив dist, хранящий минимальную цену для достижения узла из узла src. Инициализируйте его большими значениями. Инициализируйте очередь, хранящую пары {node, distance}. Изначально очередь должна содержать только {src, 0}. Создайте переменную stops и установите ее значение равным 0.

2⃣Выполняйте поиск в ширину (BFS), пока очередь не станет пустой или пока stops > k. Итерируйте по всем узлам на определенном уровне. Это будет сделано путем запуска вложенного цикла и посещения всех узлов, которые в данный момент находятся в очереди. В каждой паре {node, distance} итерируйте по всем соседям узла. Для каждого соседа проверьте, меньше ли dist[neighbor] чем distance + цена ребра. Если это так, обновите dist[neighbor] и добавьте {neighbor, dist[neighbor]} в очередь.

3⃣После итерации по всем узлам на текущем уровне увеличьте stops на один. Мы посетили все узлы на определенном уровне и готовы посетить следующий уровень узлов. Когда мы достигнем условия, при котором либо очередь станет пустой, либо stops == k, у нас будет наш ответ в dist[dst]. Если dist[dst] не изменилось с начального большого значения, значит, мы никогда не достигли его, и следует вернуть -1.

😎 Решение:
class Solution {
function findCheapestPrice($n, $flights, $src, $dst, $k) {
$adj = array_fill(0, $n, []);
foreach ($flights as $flight) {
$adj[$flight[0]][] = [$flight[1], $flight[2]];
}
$dist = array_fill(0, $n, PHP_INT_MAX);
$q = [[$src, 0]];
$stops = 0;

while ($stops <= $k && !empty($q)) {
$size = count($q);
for ($i = 0; $i < $size; $i++) {
list($node, $distance) = array_shift($q);
foreach ($adj[$node] as $neighbor) {
list($neigh, $price) = $neighbor;
if ($price + $distance >= $dist[$neigh]) continue;
$dist[$neigh] = $price + $distance;
$q[] = [$neigh, $dist[$neigh]];
}
}
$stops++;
}
return $dist[$dst] == PHP_INT_MAX ? -1 : $dist[$dst];
}
}


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

Создайте класс CombinationIterator:
CombinationIterator(string characters, int combinationLength) Инициализирует объект строкой characters, содержащей отсортированные различные строчные буквы английского алфавита, и числом combinationLength в качестве аргументов.
next() Возвращает следующую комбинацию длины combinationLength в лексикографическом порядке.
hasNext() Возвращает true, если и только если существует следующая комбинация.

Пример:
Input
["CombinationIterator", "next", "hasNext", "next", "hasNext", "next", "hasNext"]
[["abc", 2], [], [], [], [], [], []]
Output
[null, "ab", true, "ac", true, "bc", false]

Explanation
CombinationIterator itr = new CombinationIterator("abc", 2);
itr.next(); // return "ab"
itr.hasNext(); // return True
itr.next(); // return "ac"
itr.hasNext(); // return True
itr.next(); // return "bc"
itr.hasNext(); // return False


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

1⃣Сгенерируйте все возможные бинарные битовые маски длины n: от 0 до 2^n - 1.

2⃣Используйте битовые маски с k установленными битами для генерации комбинаций из k элементов. Если n - 1 - j-й бит установлен в битовой маске, это указывает на присутствие символа characters[j] в комбинации и наоборот.

3⃣Теперь у вас есть все заранее вычисленные комбинации. Извлекайте их одну за другой по каждому запросу.

😎 Решение:
class CombinationIterator {
private $combinations;

function __construct($characters, $combinationLength) {
$this->combinations = [];
$n = strlen($characters);
$k = $combinationLength;
for ($bitmask = 0; $bitmask < (1 << $n); $bitmask++) {
if (substr_count(decbin($bitmask), '1') == $k) {
$curr = [];
for ($j = 0; $j < $n; $j++) {
if ($bitmask & (1 << ($n - $j - 1))) {
$curr[] = $characters[$j];
}
}
$this->combinations[] = implode('', $curr);
}
}
}

function next() {
return array_pop($this->combinations);
}

function hasNext() {
return count($this->combinations) > 0;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 524. Longest Word in Dictionary through Deleting
Сложность: medium

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

Пример:
Input: s = "abpcplea", dictionary = ["ale","apple","monkey","plea"]
Output: "apple"


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

1⃣Инициализируйте переменную для хранения самой длинной строки, соответствующей критериям. Пройдите по каждой строке x в неотсортированном массиве dictionary и проверьте, является ли x подпоследовательностью строки s.

2⃣Если строка x является подпоследовательностью, сравните её с текущей самой длинной строкой по длине. Если длина x больше или равна длине текущей самой длинной строки и она меньше текущей строки в лексикографическом порядке (если равны по длине), обновите текущую самую длинную строку.

3⃣После рассмотрения всех строк в dictionary, верните найденную строку. Если ни одна строка не подошла, верните пустую строку.

😎 Решение:
class Solution {
function isSubsequence($x, $y) {
$j = 0;
for ($i = 0; $i < strlen($y) && $j < strlen($x); $i++) {
if ($x[$j] == $y[$i]) {
$j++;
}
}
return $j == strlen($x);
}

function findLongestWord($s, $d) {
$max_str = "";
foreach ($d as $str) {
if ($this->isSubsequence($str, $s)) {
if (strlen($str) > strlen($max_str) || (strlen($str) == strlen($max_str) && strcmp($str, $max_str) < 0)) {
$max_str = $str;
}
}
}
return $max_str;
}
}


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

Вам дан массив пар переменных equations и массив вещественных чисел values, где equations[i] = [Ai, Bi] и values[i] представляют уравнение Ai / Bi = values[i]. Каждая Ai или Bi - это строка, представляющая одну переменную. Вам также даны некоторые запросы, где queries[j] = [Cj, Dj] представляет j-й запрос, в котором вы должны найти ответ для Cj / Dj = ?. Верните ответы на все запросы. Если ни один ответ не может быть определен, верните -1.0. Замечание: входные данные всегда действительны. Можно предположить, что вычисление запросов не приведет к делению на ноль и что противоречия нет. Примечание: Переменные, которые не встречаются в списке уравнений, являются неопределенными, поэтому для них ответ не может быть определен.

Пример:
Input: equations = [["a","b"],["b","c"]], values = [2.0,3.0], queries = [["a","c"],["b","a"],["a","e"],["a","a"],["x","x"]]
Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000]


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

1⃣Создание графа:
Представьте каждую переменную как узел в графе.
Используйте уравнения для создания ребер между узлами, где каждое ребро имеет вес, равный значению уравнения (Ai / Bi = values[i]).
Создайте также обратные ребра с обратным весом (Bi / Ai = 1 / values[i]).

2⃣Поиск пути:
Для каждого запроса используйте поиск в глубину (DFS) или поиск в ширину (BFS) для поиска пути от Cj до Dj.
Если путь найден, вычислите произведение весов вдоль пути, чтобы найти значение Cj / Dj.
Если путь не найден, верните -1.0.

3⃣Обработка запросов:
Пройдитесь по всем запросам и используйте граф для вычисления результатов каждого запроса.

😎 Решение:
class Solution {
function calcEquation($equations, $values, $queries) {
$graph = [];

for ($i = 0; $i < count($equations); $i++) {
$A = $equations[$i][0];
$B = $equations[$i][1];
$value = $values[$i];
if (!isset($graph[$A])) $graph[$A] = [];
if (!isset($graph[$B])) $graph[$B] = [];
$graph[$A][$B] = $value;
$graph[$B][$A] = 1.0 / $value;
}

function bfs($start, $end, $graph) {
if (!isset($graph[$start]) || !isset($graph[$end])) return -1.0;
$queue = [[$start, 1.0]];
$visited = [];

while (!empty($queue)) {
list($current, $curProduct) = array_shift($queue);
if ($current == $end) return $curProduct;
$visited[$current] = true;
foreach ($graph[$current] as $neighbor => $value) {
if (!isset($visited[$neighbor])) {
array_push($queue, [$neighbor, $curProduct * $value]);
}
}
}
return -1.0;
}

$results = [];
foreach ($queries as $query) {
$C = $query[0];
$D = $query[1];
$results[] = bfs($C, $D, $graph);
}
return $results;
}
}


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

Дано целое число length и массив updates, где updates[i] = [startIdxi, endIdxi, inci].
У вас есть массив arr длины length, заполненный нулями. Вам нужно применить некоторые операции к arr. В i-й операции следует увеличить все элементы arr[startIdxi], arr[startIdxi + 1], ..., arr[endIdxi] на inci.
Верните arr после применения всех обновлений.

Пример:
Input: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]]
Output: [-2,0,3,5,3]


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

1⃣Для каждого обновления (start, end, val) выполните две операции:
Увеличьте значение в позиции start на val: arr[start] = arr[start] + val.
Уменьшите значение в позиции end + 1 на val: arr[end + 1] = arr[end + 1] - val.

2⃣Примените конечное преобразование: вычислите кумулятивную сумму всего массива (с индексами, начиная с 0).

3⃣Верните обновленный массив arr.

😎 Решение:
function getModifiedArray($length, $updates) {
$result = array_fill(0, $length, 0);

foreach ($updates as $update) {
list($start, $end, $val) = $update;
$result[$start] += $val;
if ($end + 1 < $length) {
$result[$end + 1] -= $val;
}
}

for ($i = 1; $i < $length; $i++) {
$result[$i] += $result[$i - 1];
}

return $result;
}


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

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

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


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

1⃣Линейно просканируйте двумерную карту, если узел содержит '1', то это корневой узел, который запускает поиск в глубину (DFS).

2⃣Во время выполнения DFS каждый посещённый узел следует установить в '0', чтобы пометить его как посещённый.

3⃣Подсчитайте количество корневых узлов, запускающих DFS. Это количество будет равно количеству островов, так как каждый DFS, начинающийся с какого-либо корня, идентифицирует остров.

😎 Решение:
class Solution {
private function dfs(&$grid, $r, $c) {
$nr = count($grid);
$nc = count($grid[0]);

if ($r < 0 || $c < 0 || $r >= $nr || $c >= $nc || $grid[$r][$c] == '0') {
return;
}

$grid[$r][$c] = '0';
$this->dfs($grid, $r - 1, $c);
$this->dfs($grid, $r + 1, $c);
$this->dfs($grid, $r, $c - 1);
$this->dfs($grid, $r, $c + 1);
}

public function numIslands($grid) {
if (empty($grid)) {
return 0;
}

$nr = count($grid);
$nc = count($grid[0]);
$numIslands = 0;

for ($r = 0; $r < $nr; ++$r) {
for ($c = 0; $c < $nc; ++$c) {
if ($grid[$r][$c] == '1') {
$numIslands++;
$this->dfs($grid, $r, $c);
}
}
}

return $numIslands;
}
}


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

Всего у вас есть numCourses курсов, которые нужно пройти, пронумерованных от 0 до numCourses - 1. Вам дан массив prerequisites, где prerequisites[i] = [ai, bi] указывает на то, что вы должны сначала пройти курс bi, если хотите взять курс ai.
Например, пара [0, 1] указывает на то, что для прохождения курса 0 сначала нужно пройти курс 1.
Верните true, если вы можете завершить все курсы. В противном случае верните false.

Пример:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.


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

1⃣Создайте массив indegree длины n, где indegree[x] хранит количество входящих рёбер в узел x. Создайте список смежности adj, в котором adj[x] содержит все узлы с входящим ребром от узла x, то есть соседей узла x. Создайте этот список смежности, итерируя prerequisites. Для каждого prerequisites добавьте ребро от prerequisites[1] к prerequisites[0] и увеличьте indegree prerequisites[0] на 1.

2⃣Инициализируйте очередь целых чисел q и начните алгоритм BFS, перемещаясь от листовых узлов к родительским узлам. Начните обход BFS, поместив все листовые узлы (indegree равное 0) в очередь. Создайте целочисленную переменную nodesVisited = 0 для подсчета количества посещенных узлов.

3⃣Пока очередь не пуста:
Извлеките первый узел из очереди.
Увеличьте nodesVisited на 1.
Для каждого соседа (узлы, которые имеют входящее ребро от узла) узла уменьшите indegree[neighbor] на 1, чтобы удалить ребро node -> neighbor.
Если indegree[neighbor] == 0, это означает, что neighbor ведет себя как листовой узел, поэтому добавьте neighbor в очередь.
Если количество посещенных узлов меньше общего количества узлов, то есть nodesVisited < n, верните false, так как должен быть цикл. В противном случае, если nodesVisited == numCourses, верните true. Можно сократить это до просто возвращения nodesVisited == numCourses.

😎 Решение:
class Solution {
function canFinish($numCourses, $prerequisites) {
$indegree = array_fill(0, $numCourses, 0);
$adj = array_fill(0, $numCourses, []);

foreach ($prerequisites as $prerequisite) {
$adj[$prerequisite[1]][] = $prerequisite[0];
$indegree[$prerequisite[0]]++;
}

$q = [];
for ($i = 0; $i < $numCourses; $i++) {
if ($indegree[$i] == 0) {
$q[] = $i;
}
}

$nodesVisited = 0;
while (!empty($q)) {
$node = array_shift($q);
$nodesVisited++;

foreach ($adj[$node] as $neighbor) {
$indegree[$neighbor]--;
if ($indegree[$neighbor] == 0) {
$q[] = $neighbor;
}
}
}

return $nodesVisited == $numCourses;
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 352. Data Stream as Disjoint Intervals
Сложность: hard

Дано поступление данных из последовательности неотрицательных целых чисел a1, a2, ..., an, необходимо обобщить увиденные числа в виде списка непересекающихся интервалов.
Реализуйте класс SummaryRanges:
SummaryRanges() Инициализирует объект с пустым потоком.
void addNum(int value) Добавляет целое число в поток.
int[][] getIntervals() Возвращает обобщение текущих чисел в потоке в виде списка непересекающихся интервалов [starti, endi]. Ответ должен быть отсортирован по starti.

Пример:
Input
["SummaryRanges", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals"]
[[], [1], [], [3], [], [7], [], [2], [], [6], []]
Output
[null, null, [[1, 1]], null, [[1, 1], [3, 3]], null, [[1, 1], [3, 3], [7, 7]], null, [[1, 3], [7, 7]], null, [[1, 3], [6, 7]]]


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

1⃣Инициализировать структуру данных TreeSet для хранения значений.

2⃣addNum(int value)
Просто добавить value в values. Если эквивалент TreeSet вашего языка программирования позволяет дублировать значения, как например SortedList в Python, нужно также проверить, что value не существует в values, так как дубликаты нарушат алгоритм.

3⃣getIntervals
Если values пуст, вернуть пустой массив.
Создать пустой список интервалов.
Установить left = right = -1. left представляет левую границу текущего интервала, а right представляет правую границу.
Итерировать по values. На каждой итерации:
Если left < 0, установить left = right = value.
Иначе, если value = right + 1, установить right = value, так как мы можем продолжить текущий интервал.
Иначе, мы не можем продолжить текущий интервал. Вставить [left, right] в intervals и установить left = right = value для начала нового интервала.
Вставить [left, right] в intervals и вернуть intervals.

😎 Решение:
class SummaryRanges {
private $values;

public function __construct() {
$this->values = [];
}

public function addNum($value) {
$this->values[$value] = true;
}

public function getIntervals() {
if (empty($this->values)) {
return [];
}

$sortedValues = array_keys($this->values);
sort($sortedValues);

$intervals = [];
$left = -1;
$right = -1;

foreach ($sortedValues as $value) {
if ($left < 0) {
$left = $right = $value;
} elseif ($value == $right + 1) {
$right = $value;
} else {
$intervals[] = [$left, $right];
$left = $right = $value;
}
}

$intervals[] = [$left, $right];
return $intervals;
}
}

// Example usage
$sr = new SummaryRanges();
$sr->addNum(1);
$sr->addNum(3);
$sr->addNum(7);
$sr->addNum(2);
$sr->addNum(6);
$intervals = $sr->getIntervals();
foreach ($intervals as $interval) {
echo $interval[0] . " " . $interval[1] . "\n";
}
?>


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

Дан массив целых чисел nums и целое число k, вернуть общее количество подмассивов, сумма которых равна k.
Подмассив - это непрерывная непустая последовательность элементов внутри массива.

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


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

1⃣Самый простой метод - рассмотреть каждый возможный подмассив данного массива nums.

2⃣Найти сумму элементов каждого из этих подмассивов и проверить равенство полученной суммы с заданным k.

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

😎 Решение:
class Solution {
function subarraySum($nums, $k) {
$count = 0;
for ($start = 0; $start < count($nums); $start++) {
for ($end = $start + 1; $end <= count($nums); $end++) {
$sum = 0;
for ($i = $start; $i < $end; $i++) {
$sum += $nums[$i];
}
if ($sum == $k) {
$count++;
}
}
}
return $count;
}
}


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

Дано целое число n, верните наименьшее количество чисел, являющихся совершенными квадратами, сумма которых равна n.
Совершенный квадрат — это целое число, являющееся квадратом целого числа; другими словами, это произведение некоторого целого числа на самого себя. Например, 1, 4, 9 и 16 являются совершенными квадратами, тогда как 3 и 11 не являются.

Пример:
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.


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

1⃣Инициализация:
Создайте массив dp размером n + 1 и заполните его значениями Integer.MAX_VALUE, кроме dp[0], которое установите в 0.
Предварительно вычислите все совершенные квадраты, которые меньше или равны n, и сохраните их в массиве square_nums.

2⃣Заполнение массива dp:
Для каждого числа i от 1 до n:
Для каждого совершенного квадрата s из массива square_nums:
Если i меньше текущего совершенного квадрата s, прервите внутренний цикл.
Обновите dp[i], чтобы он содержал минимальное количество чисел, сумма которых равна i.

3⃣Возврат результата:
Верните значение dp[n], которое будет содержать наименьшее количество совершенных квадратов, сумма которых равна n.

😎 Решение:
class Solution {
function numSquares($n) {
$dp = array_fill(0, $n + 1, PHP_INT_MAX);
$dp[0] = 0;

$maxSquareIndex = floor(sqrt($n)) + 1;
$squareNums = array_fill(0, $maxSquareIndex, 0);
for ($i = 1; $i < $maxSquareIndex; ++$i) {
$squareNums[$i] = $i * $i;
}

for ($i = 1; $i <= $n; ++$i) {
for ($s = 1; $s < $maxSquareIndex; ++$s) {
if ($i < $squareNums[$s]) break;
$dp[$i] = min($dp[$i], $dp[$i - $squareNums[$s]] + 1);
}
}

return $dp[$n];
}
}


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

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

Дан целочисленный массив hand, где hand[i] — это значение, написанное на i-й карте, и целое число groupSize. Верните true, если она может переставить карты, или false в противном случае.

Пример:
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]


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

1⃣Проверьте, делится ли длина массива hand на groupSize. Если нет, верните false.

2⃣Создайте карту cardCount для хранения количества каждой карты в массиве hand.

3⃣Итерируйте по массиву hand и обновляйте карту cardCount. Затем итерируйте снова для создания групп:
Найдите начальную карту startCard для потенциальной последовательности, уменьшая startCard, пока не найдёте карту, которая отсутствует в карте cardCount.
Попробуйте сформировать последовательность из groupSize карт, начиная с startCard. Если какая-либо карта в потенциальной последовательности отсутствует в карте cardCount, верните false.
Если последовательность можно сформировать, уменьшите количество каждой карты в последовательности в карте cardCount.

😎 Решение:
class Solution {
/**
* @param Integer[] $hand
* @param Integer $groupSize
* @return Boolean
*/
function isNStraightHand($hand, $groupSize) {
if (count($hand) % $groupSize != 0) {
return false;
}

$cardCount = [];
foreach ($hand as $card) {
if (!isset($cardCount[$card])) {
$cardCount[$card] = 0;
}
$cardCount[$card]++;
}

sort($hand);

foreach ($hand as $card) {
if ($cardCount[$card] == 0) {
continue;
}

for ($nextCard = $card; $nextCard < $card + $groupSize; $nextCard++) {
if (!isset($cardCount[$nextCard]) || $cardCount[$nextCard] == 0) {
return false;
}
$cardCount[$nextCard]--;
}
}

return true;
}
}


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

Дан целочисленный массив nums и целое число k. Верните true, если в nums есть хорошая подмассив, или false в противном случае.
Хороший подмассив — это подмассив, который:
имеет длину не менее двух, и
сумма элементов подмассива является кратной k.
Учтите:
Подмассив — это непрерывная часть массива.
Целое число x является кратным k, если существует целое число n такое, что x = n * k. Число 0 всегда является кратным k.

Пример:
Input: nums = [23,2,4,6,7], k = 6
Output: true
Explanation: [2, 4] is a continuous subarray of size 2 whose elements sum up to 6.


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

1⃣Инициализируйте целое число prefixMod = 0 и хеш-таблицу modSeen. Инициализируйте modSeen[0] значением -1, чтобы учесть начальное значение prefixMod.

2⃣Итеративно пройдите по всем элементам массива nums.

3⃣Вычислите prefixMod как (prefixMod + nums[i]) % k. Если prefixMod существует в хеш-таблице: Если размер самого длинного подмассива с модулем k составляет не менее 2, верните true. Если prefixMod не существует в хеш-таблице: Установите modSeen[prefixMod] = i. Если после завершения итерации не найден хороший подмассив, верните false.

😎 Решение:
class Solution {
function checkSubarraySum($nums, $k) {
$prefixMod = 0;
$modSeen = [0 => -1];

for ($i = 0; $i < count($nums); $i++) {
$prefixMod = ($prefixMod + $nums[$i]) % $k;

if (array_key_exists($prefixMod, $modSeen)) {
if ($i - $modSeen[$prefixMod] > 1) {
return true;
}
} else {
$modSeen[$prefixMod] = $i;
}
}

return false;
}
}


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