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

Тесты t.iss.one/+MVqzqT6ZzFFhYjhi
Вопросы собесов t.iss.one/+ajHN0OKU1okyZDky
Вакансии t.iss.one/+mX_RBWjiMTExODUy
Download Telegram
Задача: 256. Paint House
Сложность: medium

Есть ряд из n домов, где каждый дом можно покрасить в один из трёх цветов: красный, синий или зелёный. Стоимость покраски каждого дома в определённый цвет разная. Необходимо покрасить все дома так, чтобы никакие два соседних дома не были окрашены в один и тот же цвет.

Стоимость покраски каждого дома в определённый цвет представлена в виде матрицы стоимости n x 3.

Например, costs[0][0] — это стоимость покраски дома 0 в красный цвет; costs[1][2] — это стоимость покраски дома 1 в зелёный цвет и так далее...
Верните минимальную стоимость покраски всех домов.

Пример:
Input: costs = [[17,2,17],[16,16,5],[14,3,19]]
Output: 10
Explanation: Paint house 0 into blue, paint house 1 into green, paint house 2 into blue.
Minimum cost: 2 + 5 + 3 = 10.


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

1⃣Инициализируйте массив dp размера n x 3 для хранения минимальных затрат на покраску домов. Установите начальные значения для первого дома: dp[0][0] = costs[0][0], dp[0][1] = costs[0][1], dp[0][2] = costs[0][2].

2⃣Для каждого дома i от 1 до n-1 обновите значения массива dp:
dp[i][0] = costs[i][0] + min(dp[i-1][1], dp[i-1][2])
dp[i][1] = costs[i][1] + min(dp[i-1][0], dp[i-1][2])
dp[i][2] = costs[i][2] + min(dp[i-1][0], dp[i-1][1])

3⃣Верните минимальное значение из последней строки массива dp: min(dp[n-1][0], dp[n-1][1], dp[n-1][2]).

😎 Решение:
func minCost(costs [][]int) int {
n := len(costs)
dp := make([][3]int, n)
dp[0] = [3]int{costs[0][0], costs[0][1], costs[0][2]}

for i := 1; i < n; i++ {
dp[i][0] = costs[i][0] + min(dp[i-1][1], dp[i-1][2])
dp[i][1] = costs[i][1] + min(dp[i-1][0], dp[i-1][2])
dp[i][2] = costs[i][2] + min(dp[i-1][0], dp[i-1][1])
}

return min(dp[n-1][0], dp[n-1][1], dp[n-1][2])
}

func min(a, b int) int {
if a < b {
return a
}
return b
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1074. Number of Submatrices That Sum to Target
Сложность: hard

Дана матрица и целевое значение. Верните количество непустых подматриц, сумма элементов которых равна целевому значению.

Подматрица x1, y1, x2, y2 — это набор всех ячеек matrix[x][y] с x1 <= x <= x2 и y1 <= y <= y2.

Две подматрицы (x1, y1, x2, y2) и (x1', y1', x2', y2') различны, если у них есть какая-то различающаяся координата: например, если x1 != x1'.

Пример:
Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
Output: 4
Explanation: The four 1x1 submatrices that only contain 0.


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

1⃣Инициализируйте результат: count = 0. Вычислите количество строк: r = len(matrix) и количество столбцов: c = len(matrix[0]). Вычислите двумерную префиксную сумму ps, выделив еще одну строку и еще один столбец для нулевых значений.

2⃣Итерируйте по строкам: r1 от 1 до r и r2 от r1 до r. Внутри этого двойного цикла фиксируйте левые и правые границы строк и инициализируйте хэш-таблицу для хранения префиксных сумм. Итерируйте по столбцам от 1 до c + 1, вычислите текущую префиксную сумму 1D curr_sum и увеличьте count на количество матриц, сумма которых равна target.

3⃣Добавьте текущую префиксную сумму 1D в хэш-таблицу. Когда все итерации завершены, верните count.

😎 Решение:
func numSubmatrixSumTarget(matrix [][]int, target int) int {
r, c := len(matrix), len(matrix[0])
ps := make([][]int, r+1)
for i := range ps {
ps[i] = make([]int, c+1)
}

for i := 1; i <= r; i++ {
for j := 1; j <= c; j++ {
ps[i][j] = ps[i-1][j] + ps[i][j-1] - ps[i-1][j-1] + matrix[i-1][j]
}
}

count := 0

for r1 := 1; r1 <= r; r2++ {
for r2 := r1; r2 <= r; r2++ {
h := map[int]int{0: 1}
for col := 1; col <= c; col++ {
currSum := ps[r2][col] - ps[r1-1][col]
if count, ok := h[currSum-target]; ok {
count += count
}
h[currSum]++
}
}
}

return count
}


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

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

Пример:
Input: arr1 = [1,2,3,4,5], arr2 = [1,2,5,7,9], arr3 = [1,3,4,5,8]
Output: [1,5]
Explanation: Only 1 and 5 appeared in the three arrays.


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

1⃣Инициализируйте counter как TreeMap для записи чисел, которые появляются в трех массивах, и количество их появлений.

2⃣Пройдитесь по массивам arr1, arr2 и arr3, чтобы посчитать частоты появления элементов.

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

😎 Решение:
func arraysIntersection(arr1 []int, arr2 []int, arr3 []int) []int {
counter := make(map[int]int)

for _, e := range arr1 {
counter[e]++
}
for _, e := range arr2 {
counter[e]++
}
for _, e := range arr3 {
counter[e]++
}

var ans []int
for k, v := range counter {
if v == 3 {
ans = append(ans, k)
}
}

sort.Ints(ans)
return ans
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 188. Best Time to Buy and Sell Stock IV
Сложность: hard

Дан массив целых чисел prices, где prices[i] - это цена данной акции в i-й день, и целое число k.

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

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

Пример:
Input: k = 2, prices = [2,4,1]
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.


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

1⃣Инициализация DP массива: Инициализируйте трехмерный массив dp, где dp[i][j][l] представляет максимальную прибыль на конец i-го дня с j оставшимися транзакциями и l акциями в портфеле. Начните с dp[0][0][0] = 0 (нет прибыли без акций и транзакций) и dp[0][1][1] = -prices[0] (покупка первой акции).

2⃣Вычисление переходов: Для каждого дня и каждого возможного количества транзакций вычислите возможные действия: держать акцию, не держать акцию, купить акцию, если j > 0, или продать акцию. Обновляйте dp с использованием:
dp[i][j][1] = max(dp[i−1][j][1], dp[i−1][j−1][0] - prices[i]) (максимум между удержанием акции и покупкой новой).
dp[i][j][0] = max(dp[i−1][j][0], dp[i−1][j][1] + prices[i]) (максимум между неудержанием акции и продажей).

3⃣Расчет результатов: По завершении всех дней, возвращайте максимальное значение dp[n-1][j][0] для всех j от 0 до k, что представляет максимальную прибыль без удержания акций на последний день. Обработайте специальный случай, когда 𝑘×2≥𝑛, чтобы избежать лишних расчетов.

😎 Решение:
type Solution struct{}

func maxProfit(k int, prices []int) int {
n := len(prices)
if n == 0 || k == 0 {
return 0
}
if k*2 >= n {
res := 0
for i := 1; i < n; i++ {
if prices[i] > prices[i-1] {
res += prices[i] - prices[i-1]
}
}
return res
}
dp := make([][][]int, n)
for i := range dp {
dp[i] = make([][]int, k+1)
for j := range dp[i] {
dp[i][j] = make([]int, 2)
dp[i][j][0], dp[i][j][1] = -1<<31/2, -1<<31/2
}
}
dp[0][0][0] = 0
dp[0][1][1] = -prices[0]

for i := 1; i < n; i++ {
for j := 0; j <= k; j++ {
dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1]+prices[i])
if j > 0 {
dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0]-prices[i])
}
}
}
res := 0
for j := 0; j <= k; j++ {
res = max(res, dp[n-1][j][0])
}
return res
}

func max(x, y int) int {
if x > y {
return x
}
return y
}


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

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

Пример:
Input: head = [-10,-3,0,5,9]
Output: [0,-3,9,-10,null,5]
Explanation: One possible answer is [0,-3,9,-10,null,5], which represents the shown height balanced BST.


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

1⃣Поскольку нам дан односвязный список, а не массив, у нас нет прямого доступа к элементам списка по индексам. Нам нужно определить средний элемент односвязного списка. Мы можем использовать подход с двумя указателями для нахождения среднего элемента списка. В основном, у нас есть два указателя: slow_ptr и fast_ptr. slow_ptr перемещается на один узел за раз, тогда как fast_ptr перемещается на два узла за раз. К тому времени, как fast_ptr достигнет конца списка, slow_ptr окажется в середине списка. Для списка с четным количеством элементов любой из двух средних элементов может стать корнем BST.

2⃣Как только мы находим средний элемент списка, мы отсоединяем часть списка слева от среднего элемента. Мы делаем это, сохраняя prev_ptr, который указывает на узел перед slow_ptr, т.е. prev_ptr.next = slow_ptr. Для отсоединения левой части мы просто делаем prev_ptr.next = None.

3⃣Для создания сбалансированного по высоте BST нам нужно передать только голову связанного списка в функцию, которая преобразует его в BST. Таким образом, мы рекурсивно работаем с левой половиной списка, передавая оригинальную голову списка, и с правой половиной, передавая slow_ptr.next в качестве головы.

😎 Решение:
type ListNode struct {
Val int
Next *ListNode
}

type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

func sortedListToBST(head *ListNode) *TreeNode {
if head == nil {
return nil
}
mid := findMiddleElement(head)
node := &TreeNode{
Val: mid.Val,
}
if head == mid {
return node
}
node.Left = sortedListToBST(head)
node.Right = sortedListToBST(mid.Next)
return node
}

func findMiddleElement(head *ListNode) *ListNode {
var prevPtr *ListNode = nil
slowPtr := head
fastPtr := head
for fastPtr != nil && fastPtr.Next != nil {
prevPtr = slowPtr
slowPtr = slowPtr.Next
fastPtr = fastPtr.Next.Next
}
if prevPtr != nil {
prevPtr.Next = nil
}
return slowPtr
}


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

В проекте у вас есть список необходимых навыков req_skills и список людей. i-й человек people[i] содержит список навыков, которыми обладает этот человек.

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

Например, команда = [0, 1, 3] представляет людей с навыками people[0], people[1] и people[3].
Верните любую достаточную команду наименьшего возможного размера, представленную индексами каждого человека. Вы можете вернуть ответ в любом порядке.

Гарантируется, что ответ существует.

Пример:
Input: req_skills = ["algorithms","math","java","reactjs","csharp","aws"],
people = [["algorithms","math","java"],["algorithms","math","reactjs"],
["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]]
Output: [1,2]


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

1⃣Инициализация и создание масок навыков:
Определите количество людей n и количество необходимых навыков m.
Создайте хэш-таблицу skillId, чтобы сопоставить каждому навыку уникальный индекс.
Создайте массив skillsMaskOfPerson, который будет содержать битовые маски навыков для каждого человека.

2⃣Динамическое программирование (DP):
Создайте массив dp размера 2^m и заполните его значениями (1 << n) - 1.
Установите dp[0] в 0 (базовый случай).
Для каждого skillsMask от 1 до 2^m - 1:
- для каждого человека i:
- вычислите smallerSkillsMask как skillsMask & ~skillsMaskOfPerson[i].
- если smallerSkillsMask отличается от skillsMask, обновите dp[skillsMask], если новая команда лучше (имеет меньше установленных битов).

3⃣Формирование ответа:
Извлеките ответ из dp и верните массив индексов людей, составляющих минимальную достаточную команду.

😎 Решение:
import "math/bits"

func smallestSufficientTeam(req_skills []string, people [][]string) []int {
n, m := len(people), len(req_skills)
skillId := make(map[string]int)
for i, skill := range req_skills {
skillId[skill] = i
}
skillsMaskOfPerson := make([]int, n)
for i, person := range people {
for _, skill := range person {
if id, ok := skillId[skill]; ok {
skillsMaskOfPerson[i] |= 1 << id
}
}
}
dp := make([]int64, 1<<m)
for i := range dp {
dp[i] = (1 << n) - 1
}
dp[0] = 0
for skillsMask := 1; skillsMask < (1 << m); skillsMask++ {
for i := 0; i < n; i++ {
smallerSkillsMask := skillsMask &^ skillsMaskOfPerson[i]
if smallerSkillsMask != skillsMask {
peopleMask := dp[smallerSkillsMask] | (1 << i)
if bits.OnesCount64(uint64(peopleMask)) < bits.OnesCount64(uint64(dp[skillsMask])) {
dp[skillsMask] = peopleMask
}
}
}
}
answerMask := dp[(1<<m)-1]
result := []int{}
for i := 0; i < n; i++ {
if (answerMask>>i)&1 == 1 {
result = append(result, i)
}
}
return result
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1007. Minimum Domino Rotations For Equal Row
Сложность: medium

В ряду домино, tops[i] и bottoms[i] представляют собой верхнюю и нижнюю половинки i-го домино. (Домино - это плитка с двумя числами от 1 до 6 - по одному на каждой половине плитки.) Мы можем повернуть i-е домино так, чтобы tops[i] и bottoms[i] поменялись значениями. Верните минимальное количество поворотов, чтобы все значения tops были одинаковыми или все значения bottoms были одинаковыми. Если это невозможно сделать, верните -1.

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


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

1⃣Проверка кандидатов:
Для начала рассмотрим два кандидата для достижения цели: tops[0] и bottoms[0]. Это кандидаты для унификации значений в ряду домино, поскольку если есть решение, один из этих двух кандидатов должен быть в верхней или нижней строке всех домино.

2⃣Подсчет поворотов для каждого кандидата:
Для каждого из кандидатов (tops[0] и bottoms[0]) подсчитайте количество поворотов, необходимых для унификации значений во всех tops или во всех bottoms.
Если какой-либо домино не может быть повернут для достижения требуемого кандидата, этот кандидат исключается из рассмотрения.

3⃣Возврат минимального количества поворотов:
Верните минимальное количество поворотов из всех возможных кандидатов. Если ни один кандидат не подходит, верните -1.

😎 Решение:
func minDominoRotations(tops []int, bottoms []int) int {
check := func(x int) int {
rotationsA, rotationsB := 0, 0
for i := 0; i < len(tops); i++ {
if tops[i] != x && bottoms[i] != x {
return -1
} else if tops[i] != x {
rotationsA++
} else if bottoms[i] != x {
rotationsB++
}
}
return min(rotationsA, rotationsB)
}

rotations := check(tops[0])
if rotations != -1 || tops[0] == bottoms[0] {
return rotations
} else {
return check(bottoms[0])
}
}

func min(a, b int) int {
if a < b {
return a
}
return b
}


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

Создайте итератор, который поддерживает операцию peek (просмотр следующего элемента) на существующем итераторе, помимо операций hasNext (проверка наличия следующего элемента) и next (получение следующего элемента).

Реализуйте класс PeekingIterator:
PeekingIterator(Iterator<int> nums): Инициализирует объект с заданным итератором целых чисел.
int next(): Возвращает следующий элемент в массиве и перемещает указатель на следующий элемент.
boolean hasNext(): Возвращает true, если в массиве еще есть элементы.
int peek(): Возвращает следующий элемент в массиве без перемещения указателя.

Пример:
Input
["PeekingIterator", "next", "peek", "next", "next", "hasNext"]
[[[1, 2, 3]], [], [], [], [], []]
Output
[null, 1, 2, 2, 3, false]

Explanation
PeekingIterator peekingIterator = new PeekingIterator([1, 2, 3]); // [1,2,3]
peekingIterator.next(); // return 1, the pointer moves to the next element [1,2,3].
peekingIterator.peek(); // return 2, the pointer does not move [1,2,3].
peekingIterator.next(); // return 2, the pointer moves to the next element [1,2,3]
peekingIterator.next(); // return 3, the pointer moves to the next element [1,2,3]
peekingIterator.hasNext(); // return False


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

1⃣Инициализация итератора:
В конструкторе класса PeekingIterator инициализируйте итератор и проверьте, есть ли следующий элемент. Если есть, установите его как next, иначе установите next в null.

2⃣Операция peek:
Метод peek возвращает значение next, не перемещая указатель итератора.

3⃣Операции next и hasNext:
Метод next возвращает текущее значение next, обновляет next к следующему элементу в итераторе и перемещает указатель итератора. Если нет следующего элемента, бросает исключение NoSuchElementException.
Метод hasNext возвращает true, если next не равно null, и false в противном случае.

😎 Решение:
type PeekingIterator struct {
iterator Iterator
nextElem *int
}

func Constructor(iter Iterator) *PeekingIterator {
var next *int
if iter.HasNext() {
val := iter.Next()
next = &val
}
return &PeekingIterator{iterator: iter, nextElem: next}
}

func (this *PeekingIterator) hasNext() bool {
return this.nextElem != nil
}

func (this *PeekingIterator) next() int {
current := *this.nextElem
if this.iterator.HasNext() {
val := this.iterator.Next()
this.nextElem = &val
} else {
this.nextElem = nil
}
return current
}

func (this *PeekingIterator) peek() int {
return *this.nextElem
}


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

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

Примечание: нельзя использовать встроенные функции, которые оценивают строки как математические выражения, такие как eval().

Пример:
Input: s = "(1+(4+5+2)-3)+(6+8)"
Output: 23


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

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

2⃣Обработка выражения внутри скобок:
Когда встречаем открывающую скобку '(', оцениваем выражение, удаляя операнды и операторы из стека до соответствующей закрывающей скобки.
Результат выражения помещаем обратно в стек.

3⃣Финальная оценка выражения:
Продолжаем процесс до получения финального результата.
Если стек не пуст после обработки всех символов, оцениваем оставшиеся элементы как одно финальное выражение.

😎 Решение:
package main

import (
"fmt"
"math"
"strconv"
"unicode"
)

type Solution struct{}

func (s Solution) evaluateExpr(stack *[]interface{}) int {
if len(*stack) == 0 || !isInt((*stack)[len(*stack)-1]) {
*stack = append(*stack, 0)
}

res := pop(stack).(int)

for len(*stack) != 0 && (*stack)[len(*stack)-1].(rune) != ')' {
sign := pop(stack).(rune)

if sign == '+' {
res += pop(stack).(int)
} else {
res -= pop(stack).(int)
}
}
return res
}

func (s Solution) calculate(expr string) int {
operand := 0
n := 0
stack := []interface{}{}

for i := len(expr) - 1; i >= 0; i-- {
ch := expr[i]

if unicode.IsDigit(rune(ch)) {
operand = int(math.Pow(10, float64(n))) * (int(ch-'0')) + operand
n += 1
} else if ch != ' ' {
if n != 0 {
stack = append(stack, operand)
n = 0
operand = 0
}
if ch == '(' {
res := s.evaluateExpr(&stack)
pop(&stack)
stack = append(stack, res)
} else {
stack = append(stack, rune(ch))
}
}
}

if n != 0 {
stack = append(stack, operand)
}

return s.evaluateExpr(&stack)
}

func pop(stack *[]interface{}) interface{} {
if len(*stack) == 0 {
return nil
}
res := (*stack)[len(*stack)-1]
*stack = (*stack)[:len(*stack)-1]
return res
}

func isInt(value interface{}) bool {
_, ok := value.(int)
return ok
}


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

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

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


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

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

2⃣Итерируйте по отсортированному массиву и сравнивайте каждое число с следующим.

3⃣Если любое число совпадает с следующим, верните true. Если цикл завершится без совпадений, верните false.

😎 Решение:
import "sort"

func containsDuplicate(nums []int) bool {
sort.Ints(nums)
for i := 0; i < len(nums)-1; i++ {
if nums[i] == nums[i+1] {
return true
}
}
return false
}


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

Дан массив целых чисел nums длиной n, где nums является перестановкой чисел в диапазоне [0, n - 1].

Вы должны построить множество s[k] = {nums[k], nums[nums[k]], nums[nums[nums[k]]], ...} при соблюдении следующего правила:

Первый элемент в s[k] начинается с выбора элемента nums[k] с индексом k.
Следующий элемент в s[k] должен быть nums[nums[k]], затем nums[nums[nums[k]]], и так далее.
Мы прекращаем добавлять элементы непосредственно перед тем, как в s[k] появится дубликат.

Верните длину самого длинного множества s[k].

Пример:
Input: nums = [5,4,0,3,1,6,2]
Output: 4
Explanation:
nums[0] = 5, nums[1] = 4, nums[2] = 0, nums[3] = 3, nums[4] = 1, nums[5] = 6, nums[6] = 2.
One of the longest sets s[k]:
s[0] = {nums[0], nums[5], nums[6], nums[2]} = {5, 6, 2, 0}


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

1⃣Создайте массив для отслеживания посещенных элементов.

2⃣Для каждого элемента в nums, если он не посещен, начните формирование множества s[k], последовательно переходя по элементам, пока не встретится уже посещенный элемент.

3⃣Обновите максимальную длину найденного множества.

😎 Решение:
func arrayNesting(nums []int) int {
visited := make([]bool, len(nums))
maxLength := 0

for i := 0; i < len(nums); i++ {
if !visited[i] {
start := i
count := 0
for !visited[start] {
visited[start] = true
start = nums[start]
count++
}
if count > maxLength {
maxLength = count
}
}
}

return maxLength
}


Ставь 👍 и забирай 📚 Базу знаний
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⃣Соберите координаты клеток, которые могут стекать в оба океана, проверяя пересечение двух матриц достижимости.

😎 Решение:
package main

func pacificAtlantic(heights [][]int) [][]int {
m, n := len(heights), len(heights[0])
pacific := make([][]bool, m)
atlantic := make([][]bool, m)
for i := range pacific {
pacific[i] = make([]bool, n)
atlantic[i] = make([]bool, n)
}
directions := [][]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}

var dfs func(r, c int, ocean [][]bool)
dfs = func(r, c int, ocean [][]bool) {
ocean[r][c] = true
for _, dir := range directions {
nr, nc := r+dir[0], c+dir[1]
if nr >= 0 && nc >= 0 && nr < m && nc < n && !ocean[nr][nc] && heights[nr][nc] >= heights[r][c] {
dfs(nr, nc, ocean)
}
}
}

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

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


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

Вам дан вложенный список целых чисел nestedList. Каждый элемент либо является целым числом, либо списком, элементы которого также могут быть целыми числами или другими списками. Реализуйте итератор для его развёртки.

Реализуйте класс NestedIterator:

NestedIterator(List<NestedInteger> nestedList) Инициализирует итератор вложенным списком nestedList.
int next() Возвращает следующий целый элемент вложенного списка.
boolean hasNext() Возвращает true, если в вложенном списке еще остались целые числа, и false в противном случае.

Пример:
Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].


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

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

2⃣Метод next()
Возвращает следующий целый элемент из стека или очереди. Если текущий элемент является списком, развёртывайте его и добавляйте элементы в стек.

3⃣Метод hasNext()
Проверяет, есть ли в стеке или очереди оставшиеся целые элементы. Если на вершине стека находится список, развёртывайте его до тех пор, пока не встретится целый элемент.

😎 Решение:
type NestedIterator struct {
stack []*NestedInteger
}

func Constructor(nestedList []*NestedInteger) *NestedIterator {
it := &NestedIterator{}
it.flatten(nestedList)
return it
}

func (this *NestedIterator) flatten(nestedList []*NestedInteger) {
for i := len(nestedList) - 1; i >= 0; i-- {
this.stack = append(this.stack, nestedList[i])
}
}

func (this *NestedIterator) Next() int {
return this.stack[len(this.stack)-1].GetInteger()
}


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

Вам дан массив задач процессора, каждая из которых представлена буквами от A до Z, и время охлаждения, n. Каждый цикл или интервал позволяет завершить одну задачу. Задачи могут быть выполнены в любом порядке, но есть ограничение: одинаковые задачи должны быть разделены не менее чем n интервалами из-за времени охлаждения. Верните минимальное количество интервалов, необходимое для выполнения всех задач.

Пример:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8


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

1⃣Подсчитайте количество каждой задачи и найдите максимальное количество вхождений (maxFreq).

2⃣Вычислите количество интервалов, необходимых для задач с maxFreq: (maxFreq - 1) * (n + 1) + countMaxFreq, где countMaxFreq - количество задач, имеющих maxFreq.

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

😎 Решение:
package main

import (
"fmt"
"math"
)

func leastInterval(tasks []byte, n int) int {
taskCounts := make(map[byte]int)
for _, task := range tasks {
taskCounts[task]++
}

maxFreq := 0
for _, count := range taskCounts {
if count > maxFreq {
maxFreq = count
}
}

countMaxFreq := 0
for _, count := range taskCounts {
if count == maxFreq {
countMaxFreq++
}
}

return int(math.Max(float64(len(tasks)), float64((maxFreq-1)*(n+1)+countMaxFreq)))
}


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

Даны два целых числа a и b. Вернуть сумму этих двух чисел, не используя операторы + и -.

Пример:
Input: a = 1, b = 2
Output: 3


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

1⃣Упростите задачу до двух случаев: сумма или вычитание двух положительных целых чисел: x ± y, где x > y. Запомните знак результата.

2⃣Если нужно вычислить сумму:
Пока перенос не равен нулю (y != 0):
Текущий ответ без переноса равен XOR x и y: answer = x ^ y.
Текущий перенос равен сдвинутому влево AND x и y: carry = (x & y) << 1.
Подготовьтесь к следующему циклу: x = answer, y = carry.
Верните x * sign.

3⃣Если нужно вычислить разность:
Пока заимствование не равно нулю (y != 0):
Текущий ответ без заимствования равен XOR x и y: answer = x ^ y.
Текущее заимствование равно сдвинутому влево AND НЕ x и y: borrow = ((~x) & y) << 1.
Подготовьтесь к следующему циклу: x = answer, y = borrow.
Верните x * sign.

😎 Решение:
package main

import "math"

func getSum(a int, b int) int {
x, y := int(math.Abs(float64(a))), int(math.Abs(float64(b)))
if x < y {
return getSum(b, a)
}
sign := 1
if a < 0 {
sign = -1
}

if a * b >= 0 {
for y != 0 {
carry := (x & y) << 1
x ^= y
y = carry
}
} else {
for y != 0 {
borrow := ((^x) & y) << 1
x ^= y
y = borrow
}
}
return x * sign
}


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

Вам дана строка s из строчных букв английского алфавита и целочисленный массив shifts такой же длины.

Назовем shift() буквы следующей буквой в алфавите (с переходом так, что 'z' становится 'a').
Например, shift('a') = 'b', shift('t') = 'u', и shift('z') = 'a'.
Теперь для каждого shifts[i] = x мы хотим сдвинуть первые i + 1 букв строки s на x раз.

Верните итоговую строку после применения всех таких сдвигов к s.

Пример:
Input: s = "abc", shifts = [3,5,9]
Output: "rpl"
Explanation: We start with "abc".
After shifting the first 1 letters of s by 3, we have "dbc".
After shifting the first 2 letters of s by 5, we have "igc".
After shifting the first 3 letters of s by 9, we have "rpl", the answer.


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

1⃣Вычислите общее количество сдвигов для всех символов строки, используя массив shifts.

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

3⃣Постройте и верните итоговую строку после всех сдвигов.

😎 Решение:
func shiftingLetters(s string, shifts []int) string {
totalShifts := 0
for _, shift := range shifts {
totalShifts = (totalShifts + shift) % 26
}

result := make([]byte, len(s))
for i := 0; i < len(s); i++ {
newCharValue := (int(s[i]-'a') + totalShifts) % 26
result[i] = byte(newCharValue + 'a')
totalShifts = (totalShifts - shifts[i] + 26) % 26
}

return string(result)
}


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

Учитывая url startUrl и интерфейс HtmlParser, реализуйте веб-краулер для просмотра всех ссылок, которые находятся под тем же именем хоста, что и startUrl.Верните все ссылки, полученные вашим краулером, в любом порядке. Ваш краулер должен: Начинать со страницы: startUrl Вызывать HtmlParser.getUrls(url), чтобы получить все ссылки с веб-страницы с заданным url. Не просматривайте одну и ту же ссылку дважды. Исследуйте только те ссылки, которые находятся под тем же именем хоста, что и startUrl. Как показано в примере url выше, имя хоста - example.org. Для простоты можно считать, что все урлы используют протокол http без указания порта. Например, урлы https://leetcode.com/problems и https://leetcode.com/contest находятся под одним и тем же именем хоста, а урлы https://example.org/test и https://example.com/abc не находятся под одним и тем же именем хоста.

Пример:
Input:
urls = [
"https://news.yahoo.com",
"https://news.yahoo.com/news",
"https://news.yahoo.com/news/topics/",
"https://news.google.com",
"https://news.yahoo.com/us"
]
edges = [[2,0],[2,1],[3,2],[3,1],[0,4]]
startUrl = "https://news.yahoo.com/news/topics/"
Output: [
"https://news.yahoo.com",
"https://news.yahoo.com/news",
"https://news.yahoo.com/news/topics/",
"https://news.yahoo.com/us"
]


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

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

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

3⃣Если да, и если мы еще не посещали эту ссылку, добавляем ее в очередь и отмечаем как посещенную.

😎 Решение:
package main

import (
"net/url"
"strings"
)

type HtmlParser interface {
GetUrls(url string) []string
}

func extractHostname(rawurl string) string {
parsedUrl, err := url.Parse(rawurl)
if err != nil {
return ""
}
return parsedUrl.Host
}

func crawl(startUrl string, htmlParser HtmlParser) []string {
hostname := extractHostname(startUrl)
visited := make(map[string]bool)
queue := []string{startUrl}
visited[startUrl] = true

for len(queue) > 0 {
url := queue[0]
queue = queue[1:]

for _, nextUrl := range htmlParser.GetUrls(url) {
if !visited[nextUrl] && extractHostname(nextUrl) == hostname {
visited[nextUrl] = true
queue = append(queue, nextUrl)
}
}
}

result := []string{}
for url := range visited {
result = append(result, url)
}

return result
}


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

Вам дана голова связного списка с n узлами. Для каждого узла в списке найдите значение следующего большего узла. То есть для каждого узла найдите значение первого узла, который находится рядом с ним и имеет строго большее значение, чем он. Верните целочисленный массив answer, где answer[i] - это значение следующего большего узла ith-узла (с индексацией по 1). Если у узла ith нет следующего большего узла, установите answer[i] = 0.

Пример:
Input: head = [2,1,5]
Output: [5,5,0]


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

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

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

3⃣Заполнение оставшихся значений:
Для всех индексов, оставшихся в стеке, установите значение ответа равным 0, так как для них не найдено большего элемента.

😎 Решение:
type ListNode struct {
Val int
Next *ListNode
}

func nextLargerNodes(head *ListNode) []int {
var values []int
for head != nil {
values = append(values, head.Val)
head = head.Next
}

answer := make([]int, len(values))
stack := []int{}

for i, value := range values {
for len(stack) > 0 && values[stack[len(stack)-1]] < value {
answer[stack[len(stack)-1]] = value
stack = stack[:len(stack)-1]
}
stack = append(stack, i)
}

return answer
}


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

Дан корень бинарного дерева, инвертируйте дерево и верните его корень.

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


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

1⃣Рекурсивная инверсия поддеревьев:
Если текущий узел (root) пустой, возвращаем null.
Рекурсивно инвертируем правое поддерево и сохраняем результат в переменную right.
Рекурсивно инвертируем левое поддерево и сохраняем результат в переменную left.

2⃣Обмен поддеревьев:
Устанавливаем левое поддерево текущего узла равным правому поддереву.
Устанавливаем правое поддерево текущего узла равным левому поддереву.

3⃣Возврат корня:
Возвращаем текущий узел (root) как новый корень инвертированного дерева.

😎 Решение:
package main

import "fmt"

type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}

func invertTree(root *TreeNode) *TreeNode {
if root == nil {
return nil
}
right := invertTree(root.Right)
left := invertTree(root.Left)
root.Left = right
root.Right = left
return root
}


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

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

Вы должны написать алгоритм со сложностью O(log n).

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


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

1⃣Инициализировать два указателя: left = 0, right = n - 1.

2⃣Бинарный поиск:
- Вычислить pivot = left + (right - left) / 2.
- Если nums[pivot] == target, вернуть pivot.
- Если target < nums[pivot], искать в левом подмассиве (right = pivot - 1).
- Если target > nums[pivot], искать в правом подмассиве (left = pivot + 1).

3⃣Вернуть `left` – это позиция, где target должен быть вставлен.

😎Решение:
func searchInsert(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
pivot := left + (right-left)/2
if nums[pivot] == target {
return pivot
} else if target < nums[pivot] {
right = pivot - 1
} else {
left = pivot + 1
}
}
return left
}


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