Golang | LeetCode
3.91K 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
#medium
Задача: 636. Exclusive Time of Functions

На однопоточном процессоре выполняется программа, содержащая n функций. Каждая функция имеет уникальный ID от 0 до n-1. Вызовы функций хранятся в стеке вызовов: когда начинается вызов функции, ее ID заталкивается в стек, а когда вызов функции заканчивается, ее ID выгружается из стека. Функция, чей идентификатор находится в верхней части стека, является текущей выполняемой функцией. Каждый раз, когда функция запускается или завершается, мы пишем лог с идентификатором, началом или завершением и меткой времени. Вам предоставляется список logs, где logs[i] представляет собой i-е сообщение лога, отформатированное как строка "{function_id}:{"start" | "end"}:{timestamp}". Например, "0:start:3" означает, что вызов функции с идентификатором 0 начался в начале временной метки 3, а "1:end:2" означает, что вызов функции с идентификатором 1 завершился в конце временной метки 2. Обратите внимание, что функция может быть вызвана несколько раз, возможно, рекурсивно. Исключительное время функции - это сумма времен выполнения всех вызовов функции в программе. Например, если функция вызывается дважды, причем один вызов выполняется за 2 единицы времени, а другой - за 1 единицу, то эксклюзивное время равно 2 + 1 = 3. Верните эксклюзивное время каждой функции в массив, где значение по i-му индексу представляет собой эксклюзивное время для функции с идентификатором i.

Пример:
Input: n = 2, logs = ["0:start:0","1:start:2","1:end:5","0:end:6"]
Output: [3,4]


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

1⃣Парсинг логов
Пройдитесь по каждому логу, чтобы распознать действие (start или end) и идентификатор функции вместе с временной меткой.

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

3⃣Обновление времени выполнения
Когда функция завершает выполнение, обновите ее эксклюзивное время и также учитывайте время выполнения вложенных функций.

😎 Решение:
package main

import (
"fmt"
"strconv"
"strings"
)

func exclusiveTime(n int, logs []string) []int {
stack := []int{}
times := make([]int, n)
prevTime := 0

for _, log := range logs {
parts := strings.Split(log, ":")
fid, _ := strconv.Atoi(parts[0])
typ := parts[1]
time, _ := strconv.Atoi(parts[2])

if typ == "start" {
if len(stack) > 0 {
times[stack[len(stack)-1]] += time - prevTime
}
stack = append(stack, fid)
prevTime = time
} else {
times[stack[len(stack)-1]] += time - prevTime + 1
stack = stack[:len(stack)-1]
prevTime = time + 1
}
}

return times
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#easy
Задача: 637. Average of Levels in Binary Tree

Учитывая корень бинарного дерева, верните среднее значение узлов на каждом уровне в виде массива. Принимаются ответы в пределах 10-5 от фактического ответа.

Пример:
Input: root = [3,9,20,null,null,15,7]
Output: [3.00000,14.50000,11.00000]


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

1⃣Обход дерева
Используйте обход в ширину (BFS) для обхода каждого уровня дерева.

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

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

😎 Решение:
package main

import (
"container/list"
)

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

func averageOfLevels(root *TreeNode) []float64 {
var result []float64
queue := list.New()
queue.PushBack(root)

for queue.Len() > 0 {
levelSum := 0
levelCount := queue.Len()
for i := 0; i < levelCount; i++ {
node := queue.Remove(queue.Front()).(*TreeNode)
levelSum += node.Val
if node.Left != nil {
queue.PushBack(node.Left)
}
if node.Right != nil {
queue.PushBack(node.Right)
}
}
result = append(result, float64(levelSum)/float64(levelCount))
}

return result
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#medium
Задача: 638. Shopping Offers

В магазине LeetCode Store есть n предметов для продажи. Каждый товар имеет свою цену. Однако существуют специальные предложения, и специальное предложение состоит из одного или нескольких различных видов товаров с распродажной ценой. Вам дан целочисленный массив price, где price[i] - цена i-го товара, и целочисленный массив needs, где needs[i] - количество штук i-го товара, который вы хотите купить. Вам также дан массив special, где special[i] имеет размер n + 1, где special[i][j] - количество штук j-го товара в i-м предложении, а special[i][n] (т.е., Возвращает наименьшую цену, которую вы можете заплатить за определенный товар из заданных, где вы могли бы оптимально использовать специальные предложения. Вам не разрешается покупать больше товаров, чем вы хотите, даже если это снизит общую цену. Вы можете использовать любое из специальных предложений столько раз, сколько захотите.

Пример:
Input: price = [2,5], special = [[3,0,5],[1,2,10]], needs = [3,2]
Output: 14


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

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

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

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

😎 Решение:
package main

import (
"fmt"
"strconv"
"strings"
)

func shoppingOffers(price []int, special [][]int, needs []int) int {
memo := make(map[string]int)
return dfs(price, special, needs, memo)
}

func dfs(price []int, special [][]int, needs []int, memo map[string]int) int {
key := serialize(needs)
if val, exists := memo[key]; exists {
return val
}

minPrice := 0
for i := 0; i < len(needs); i++ {
minPrice += needs[i] * price[i]
}

for _, offer := range special {
newNeeds := make([]int, len(needs))
valid := true
for i := 0; i < len(needs); i++ {
if needs[i] < offer[i] {
valid = false
break
}
newNeeds[i] = needs[i] - offer[i]
}
if valid {
minPrice = min(minPrice, offer[len(needs)]+dfs(price, special, newNeeds, memo))
}
}

memo[key] = minPrice
return minPrice
}

func serialize(needs []int) string {
var sb strings.Builder
for _, need := range needs {
sb.WriteString(strconv.Itoa(need))
sb.WriteString(",")
}
return sb.String()
}

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


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#hard
Задача: 639. Decode Ways II

Сообщение, содержащее буквы от 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". В дополнение к вышеуказанным преобразованиям кодированное сообщение может содержать символ "*", который может представлять любую цифру от "1" до "9" ("0" исключается). Например, кодированное сообщение "1*" может представлять любое из кодированных сообщений "11", "12", "13", "14", "15", "16", "17", "18" или "19". Декодирование "1*" эквивалентно декодированию любого из кодированных сообщений, которые оно может представлять. Если задана строка s, состоящая из цифр и символов '*', верните количество способов ее декодирования. Поскольку ответ может быть очень большим, верните его по модулю 109 + 7.

Пример:
Input: s = "*"
Output: 9


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

1⃣Инициализация
Создайте массив dp, где dp[i] представляет количество способов декодирования подстроки s[0:i]. Установите начальные значения dp[0] = 1 (пустая строка имеет один способ декодирования).

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

3⃣Модульное вычисление
Поскольку количество способов декодирования может быть большим, вычисляйте результаты по модулю 10^9 + 7.

😎 Решение:
package main

import (
"fmt"
)

func numDecodings(s string) int {
const MOD = 1000000007
n := len(s)
dp := make([]int, n+1)
dp[0] = 1

for i := 1; i <= n; i++ {
if s[i-1] == '*' {
dp[i] = 9 * dp[i-1]
} else if s[i-1] != '0' {
dp[i] = dp[i-1]
}

if i > 1 {
if s[i-2] == '*' {
if s[i-1] == '*' {
dp[i] += 15 * dp[i-2]
} else if s[i-1] >= '0' && s[i-1] <= '6' {
dp[i] += 2 * dp[i-2]
} else {
dp[i] += dp[i-2]
}
} else if s[i-2] == '1' {
if s[i-1] == '*' {
dp[i] += 9 * dp[i-2]
} else {
dp[i] += dp[i-2]
}
} else if s[i-2] == '2' {
if s[i-1] == '*' {
dp[i] += 6 * dp[i-2]
} else if s[i-1] >= '0' && s[i-1] <= '6' {
dp[i] += dp[i-2]
}
}
}

dp[i] %= MOD
}

return dp[n]
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#medium
Задача: 640. Solve the Equation

Решите заданное уравнение и верните значение 'x' в виде строки "x=#value". Уравнение содержит только операции '+', '-', переменную 'x' и ее коэффициент. Вы должны вернуть "No solution", если для уравнения нет решения, или "Infinite solutions", если для уравнения существует бесконечное количество решений. Если для уравнения существует ровно одно решение, мы убеждаемся, что значение 'x' является целым числом.

Пример:
Input: s = "*"
Output: 9


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

1⃣Разделение уравнения
Разделите уравнение на левую и правую части относительно знака равенства '='.

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

3⃣Решение уравнения
Используйте уравнение вида ax + b = cx + d, чтобы решить для 'x'. Если коэффициенты 'x' равны и числовые значения равны, уравнение имеет бесконечное количество решений. Если коэффициенты 'x' равны, но числовые значения различны, решения нет. В противном случае вычислите значение 'x'.

😎 Решение:
package main

import (
"fmt"
"strconv"
"strings"
)

func solveEquation(equation string) string {
parse := func(s string) (int, int) {
coeff, constPart, sign, num := 0, 0, 1, 0
i := 0
for i < len(s) {
if s[i] == '+' {
sign = 1
i++
} else if s[i] == '-' {
sign = -1
i++
} else if s[i] >= '0' && s[i] <= '9' {
num = 0
for i < len(s) && s[i] >= '0' && s[i] <= '9' {
num = num*10 + int(s[i]-'0')
i++
}
if i < len(s) && s[i] == 'x' {
coeff += sign * num
i++
} else {
constPart += sign * num
}
} else if s[i] == 'x' {
coeff += sign
i++
}
}
return coeff, constPart
}

left, right := equation[:strings.Index(equation, "=")], equation[strings.Index(equation, "=")+1:]
leftCoeff, leftConst := parse(left)
rightCoeff, rightConst := parse(right)

coeff := leftCoeff - rightCoeff
constPart := rightConst - leftConst

if coeff == 0 {
if constPart == 0 {
return "Infinite solutions"
}
return "No solution"
}
return "x=" + strconv.Itoa(constPart/coeff)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
#easy
Задача: 566. Reshape the Matrix

В MATLAB есть удобная функция под названием reshape, которая может преобразовать матрицу размером m x n в новую матрицу с другим размером r x c, сохраняя исходные данные.

Вам дана матрица m x n mat и два целых числа r и c, представляющие количество строк и столбцов желаемой преобразованной матрицы.

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

Если операция преобразования с заданными параметрами возможна и допустима, выведите новую преобразованную матрицу; в противном случае выведите исходную матрицу.

Пример:
Input: mat = [[1,2],[3,4]], r = 1, c = 4
Output: [[1,2,3,4]]


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

1⃣Проверить, можно ли преобразовать матрицу с заданными параметрами r и c. Это возможно, если произведение m * n равно произведению r * c. Если преобразование невозможно, вернуть исходную матрицу.

2⃣Создать новый массив для хранения преобразованной матрицы. Перебрать все элементы исходной матрицы и вставить их в новый массив в порядке обхода строк.

3⃣Вернуть преобразованную матрицу, если преобразование возможно, иначе вернуть исходную матрицу.

😎 Решение:
func matrixReshape(mat [][]int, r int, c int) [][]int {
m, n := len(mat), len(mat[0])
if m*n != r*c {
return mat
}
reshapedMatrix := make([][]int, r)
for i := range reshapedMatrix {
reshapedMatrix[i] = make([]int, c)
}
row, col := 0, 0
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
reshapedMatrix[row][col] = mat[i][j]
col++
if col == c {
col = 0
row++
}
}
}
return reshapedMatrix
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#medium
Задача: 641. Design Circular Deque

Разработайте свою реализацию круговой двусторонней очереди (deque). Реализуйте класс MyCircularDeque: MyCircularDeque(int k) Инициализирует deque с максимальным размером k. boolean insertFront() Добавляет элемент в переднюю часть Deque. Возвращает true, если операция прошла успешно, или false в противном случае. boolean insertLast() Добавляет элемент в заднюю часть Deque. Возвращает true, если операция выполнена успешно, или false в противном случае. boolean deleteFront() Удаляет элемент из передней части Deque. Возвращает true, если операция прошла успешно, или false в противном случае. boolean deleteLast() Удаляет элемент из задней части Deque. Возвращает true, если операция прошла успешно, или false в противном случае. int getFront() Возвращает передний элемент из Deque. Возвращает -1, если Deque пуст. int getRear() Возвращает последний элемент из Deque. Возвращает -1, если Deque пуст. boolean isEmpty() Возвращает true, если Deque пуст, или false в противном случае. boolean isFull() Возвращает true, если Deque полон, или false в противном случае.

Пример:
Input
["MyCircularDeque", "insertLast", "insertLast", "insertFront", "insertFront", "getRear", "isFull", "deleteLast", "insertFront", "getFront"]
[[3], [1], [2], [3], [4], [], [], [], [4], []]
Output
[null, true, true, true, false, 2, true, true, true, 4]


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

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

2⃣Операции вставки
Реализуйте методы вставки элементов в переднюю и заднюю части очереди с учетом кольцевой структуры.

3⃣Операции удаления
Реализуйте методы удаления элементов из передней и задней частей очереди с учетом кольцевой структуры и методы для получения переднего и заднего элементов очереди.

😎 Решение:
package main

type MyCircularDeque struct {
deque []int
front int
rear int
size int
capacity int
}

func Constructor(k int) MyCircularDeque {
return MyCircularDeque{
deque: make([]int, k),
front: 0,
rear: 0,
size: 0,
capacity: k,
}
}

func (this *MyCircularDeque) InsertFront(value int) bool {
if this.IsFull() {
return false
}
this.front = (this.front - 1 + this.capacity) % this.capacity
this.deque[this.front] = value
this.size++
return true
}

func (this *MyCircularDeque) InsertLast(value int) bool {
if this.IsFull() {
return false
}
this.deque[this.rear] = value
this.rear = (this.rear + 1) % this.capacity
this.size++
return true
}

func (this *MyCircularDeque) DeleteFront() bool {
if this.IsEmpty() {
return false
}
this.front = (this.front + 1) % this.capacity
this.size--
return true
}

func (this *MyCircularDeque) DeleteLast() bool {
if this.IsEmpty() {
return false
}
this.rear = (this.rear - 1 + this.capacity) % this.capacity
this.size--
return true
}

func (this *MyCircularDeque) GetFront() int {
if this.IsEmpty() {
return -1
}
return this.deque[this.front]
}

func (this *MyCircularDeque) GetRear() int {
if this.IsEmpty() {
return -1
}
return this.deque[(this.rear-1+this.capacity)%this.capacity]
}

func (this *MyCircularDeque) IsEmpty() bool {
return this.size == 0
}

func (this *MyCircularDeque) IsFull() bool {
return this.size == this.capacity
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#medium
Задача: 567. Permutation in String

Даны две строки s1 и s2. Верните true, если s2 содержит перестановку s1, или false в противном случае.

Другими словами, верните true, если одна из перестановок s1 является подстрокой s2.

Пример:
Input: s1 = "ab", s2 = "eidbaooo"
Output: true
Explanation: s2 contains one permutation of s1 ("ba").


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

1⃣Создать массив для подсчета символов в строке s1. Затем создать аналогичный массив для первых len(s1) символов строки s2.

2⃣Использовать скользящее окно для перемещения по строке s2. Для каждой позиции окна обновлять массив подсчета символов и сравнивать его с массивом для строки s1.

3⃣Если массивы совпадают на любом этапе, вернуть true. Если окно достигает конца строки s2 и совпадений не найдено, вернуть false.

😎 Решение:
func checkInclusion(s1 string, s2 string) bool {
s1Len, s2Len := len(s1), len(s2)
if s1Len > s2Len {
return false
}

s1Count, s2Count := make([]int, 26), make([]int, 26)
for i := 0; i < s1Len; i++ {
s1Count[s1[i]-'a']++
s2Count[s2[i]-'a']++
}

for i := 0; i < s2Len-s1Len; i++ {
if equal(s1Count, s2Count) {
return true
}
s2Count[s2[i]-'a']--
s2Count[s2[i+s1Len]-'a']++
}

return equal(s1Count, s2Count)
}

func equal(a, b []int) bool {
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#hard
Задача: 568. Maximum Vacation Days

LeetCode хочет предоставить одному из своих лучших сотрудников возможность путешествовать по n городам для сбора задач по алгоритмам. Однако, как говорится, "делу время, потехе час". Вы можете брать отпуска в некоторых конкретных городах и неделях. Ваша задача — спланировать поездку, чтобы максимально увеличить количество дней отпуска, которые вы сможете взять, соблюдая при этом определенные правила и ограничения.

Правила и ограничения:
Вы можете путешествовать только между n городами, обозначенными индексами от 0 до n-1. Изначально вы находитесь в городе с индексом 0 в понедельник.
Города связаны рейсами. Рейсы представлены матрицей n x n, называемой flights, представляющей статус авиалинии от города i до города j. Если рейса из города i в город j нет, flights[i][j] == 0; иначе flights[i][j] == 1. Также для всех i выполняется flights[i][i] == 0.
У вас есть k недель (каждая неделя состоит из семи дней) для путешествий. Вы можете летать не более одного раза в день и можете летать только утром каждого понедельника. Время полета настолько короткое, что его влияние не учитывается.
Для каждого города у вас есть ограниченные дни отпуска в разные недели, заданные матрицей n x k, называемой days. Значение days[i][j] представляет максимальное количество дней отпуска, которые вы можете взять в городе i на неделе j.
Даны две матрицы flights и days, верните максимальное количество дней отпуска, которые вы можете взять в течение k недель.

Пример:
Input: flights = [[0,1,1],[1,0,1],[1,1,0]], days = [[1,3,1],[6,0,3],[3,3,3]]
Output: 12
Explanation:
One of the best strategies is:
1st week : fly from city 0 to city 1 on Monday, and play 6 days and work 1 day.
(Although you start at city 0, we could also fly to and start at other cities since it is Monday.)
2nd week : fly from city 1 to city 2 on Monday, and play 3 days and work 4 days.
3rd week : stay at city 2, and play 3 days and work 4 days.
Ans = 6 + 3 + 3 = 12.


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

1⃣Использовать функцию dfs (поиск в глубину), которая возвращает количество отпускных дней, которые можно взять, начиная с текущего города cur_city и текущей недели weekno. В каждом вызове функции проходить по всем городам и находить все города, которые связаны с текущим городом. Такой город обозначен 1 в соответствующей позиции flights[cur_city][i].

2⃣Для текущего города можно либо остаться в нем, либо поехать в связанный город. Обозначим город, в который меняется расположение, как j. После смены города нужно найти количество отпускных дней, которые можно взять, начиная с нового города и с новой недели. Это количество отпускных дней можно представить как: days[j][weekno] + dfs(flights, days, j, weekno + 1).

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

😎 Решение:
func maxVacationDays(flights [][]int, days [][]int) int {
n, k := len(flights), len(days[0])
memo := make([][]int, n)
for i := range memo {
memo[i] = make([]int, k)
for j := range memo[i] {
memo[i][j] = -1
}
}
return dfs(flights, days, memo, 0, 0)
}

func dfs(flights [][]int, days [][]int, memo [][]int, curCity, weekNo int) int {
n, k := len(flights), len(days[0])
if weekNo == k {
return 0
}
if memo[curCity][weekNo] != -1 {
return memo[curCity][weekNo]
}
maxVac := 0
for nextCity := 0; nextCity < n; nextCity++ {
if curCity == nextCity || flights[curCity][nextCity] == 1 {
maxVac = max(maxVac, days[nextCity][weekNo]+dfs(flights, days, memo, nextCity, weekNo+1))
}
}
memo[curCity][weekNo] = maxVac
return maxVac
}

func max(a, b int) int {
if a > b {
return a
}
return b
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#easy
Задача: CodeTestcaseTest ResultTest Result1523. Count Odd Numbers in an Interval Range

### Условие задачи

Даны два неотрицательных целых числа low и high. Верните количество нечётных чисел между low и high (включительно).

Пример:
Input: low = 3, high = 7
Output: 3
Explanation: The odd numbers between 3 and 7 are [3,5,7].


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

1️⃣ Проверьте, является ли число low нечётным. Это можно легко сделать с помощью оператора %, но мы используем побитовый оператор &, так как он более эффективен.

2️⃣ Если low нечётное, увеличьте его на 1.

3️⃣ Верните (high - low) / 2 + 1. Важный момент здесь - проверить, не стало ли low больше, чем high после увеличения. Это произойдёт, если low = high, и в этом случае следует вернуть 0.

😎 Решение🐍
func countOdds(low int, high int) int {
if (low & 1 == 0 {
low++
}
if low > high {
return 0
}
return (high - low) / 2 + 1
}


🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
1
#medium
Задача: 1522. Diameter of N-Ary Tree

Дано корневое дерево N-арности, нужно вычислить длину диаметра дерева.

Диаметр N-арного дерева - это длина самого длинного пути между любыми двумя узлами в дереве. Этот путь может проходить или не проходить через корень.

(Входная сериализация N-арного дерева представлена их обходом в порядке уровней, каждая группа дочерних узлов разделена значением null.)

Пример:
Input: root = [1,null,3,2,4,null,5,6]
Output: 3
Explanation: Diameter is shown in red color.


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

1️⃣ Определите функцию height(node), которая возвращает высоту узла. Функция может быть реализована рекурсивно, основываясь на вычислении максимальной высоты среди всех дочерних узлов плюс один.

2️⃣ Внутри функции height(node) выберите две наибольшие высоты среди дочерних узлов. Эти два значения помогут вычислить длину пути, которая будет кандидатом на диаметр всего дерева.

3️⃣ Существует два подхода для выбора двух наибольших высот:
— Первый способ заключается в хранении высот всех дочерних узлов в массиве, последующей сортировке массива и выборе двух наибольших элементов.
— Второй способ использует две переменные, которые отслеживают текущие два наибольших значения. Во время итерации по всем высотам эти переменные обновляются соответствующим образом.

😎 Решение🐍
type Node struct {
Val int
Children []*Node
}

type Solution struct {
diameter int
}

func (s *Solution) height(node *Node) int {
if len(node.Children) == 0 {
return 0
}

maxHeight1, maxHeight2 := 0, 0
for _, child := range node.Children {
parentHeight := s.height(child) + 1
if parentHeight > maxHeight1 {
maxHeight2 = maxHeight1
maxHeight1 = parentHeight
} else if parentHeight > maxHeight2 {
maxHeight2 = parentHeight
}
distance := maxHeight1 + maxHeight2
if distance > s.diameter {
s.diameter = distance
}
}

return maxHeight1
}

func (s *Solution) Diameter(root *Node) int {
s.diameter = 0
s.height(root)
return s.diameter
}


🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
#medium
Задача: 1519. Number of Nodes in the Sub-Tree With the Same Label

Вам дано дерево (т.е. связный неориентированный граф без циклов), состоящее из n узлов, пронумерованных от 0 до n - 1, и ровно n - 1 ребра. Корнем дерева является узел 0, и каждый узел дерева имеет метку, которая является строчной буквой, указанной в строке labels (т.е. узел с номером i имеет метку labels[i]).

Массив edges дан в форме edges[i] = [ai, bi], что означает, что существует ребро между узлами ai и bi в дереве.

Верните массив размера n, где ans[i] — это количество узлов в поддереве узла i, которые имеют ту же метку, что и узел i.

Поддерево дерева T — это дерево, состоящее из узла в T и всех его дочерних узлов.

Пример:
Input: n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd"
Output: [2,1,1,1,1,1,1]
Explanation: Node 0 has label 'a' and its sub-tree has node 2 with label 'a' as well, thus the answer is 2. Notice that any node is part of its sub-tree.
Node 1 has a label 'b'. The sub-tree of node 1 contains nodes 1,4 and 5, as nodes 4 and 5 have different labels than node 1, the answer is just 1 (the node itself).


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

1️⃣ Создайте список смежности, где adj[X] содержит всех соседей узла X.

2️⃣ Инициализируйте массив ans, хранящий ответ для каждого узла, и заполните его нулями.

3️⃣ Начните обход в глубину (DFS).

😎 Решение🐍
func dfs(node, parent int, adj map[int][]int, labels string, ans []int) []int {
nodeCounts := make([]int, 26)
nodeCounts[labels[node]-'a'] = 1

for _, child := range adj[node] {
if child == parent {
continue
}
childCounts := dfs(child, node, adj, labels, ans)
for i := 0; i < 26; i++ {
nodeCounts[i] += childCounts[i]
}
}

ans[node] = nodeCounts[labels[node]-'a']
return nodeCounts
}

func countSubTrees(n int, edges [][]int, labels string) []int {
adj := make(map[int][]int)
for _, edge := range edges {
adj[edge[0]] = append(adj[edge[0]], edge[1])
adj[edge[1]] = append(adj[edge[1]], edge[0])
}

ans := make([]int, n)
dfs(0, -1, adj, labels, ans)
return ans
}


🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
#easy
Задача: 1518. Water Bottles

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

Операция питья полной бутылки воды превращает её в пустую бутылку.

Даны два целых числа 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.

😎 Решение🐍
func numWaterBottles(numBottles int, numExchange int) int {
consumedBottles := 0

for numBottles >= numExchange {
consumedBottles += numExchange
numBottles -= numExchange
numBottles++
}

return consumedBottles + numBottles
}


🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
#easy
Задача: 643. Maximum Average Subarray I

Вам дан целочисленный массив nums, состоящий из n элементов, и целое число k. Найдите смежный подмассив, длина которого равна k и который имеет максимальное среднее значение, и верните это значение. Принимается любой ответ с погрешностью вычислений менее 10-5.

Пример:
Input: nums = [1,12,-5,-6,50,3], k = 4
Output: 12.75000


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

1⃣Инициализация скользящего окна
Вычислите сумму первых k элементов массива nums. Это будет начальное значение максимальной суммы.

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

3⃣Обновление максимальной суммы
На каждом шаге обновляйте максимальную сумму, если текущая сумма больше, и в конце верните среднее значение этой суммы.

😎 Решение:
package main

func findMaxAverage(nums []int, k int) float64 {
currentSum := 0
for i := 0; i < k; i++ {
currentSum += nums[i]
}
maxSum := currentSum

for i := k; i < len(nums); i++ {
currentSum += nums[i] - nums[i - k]
if currentSum > maxSum {
maxSum = currentSum
}
}

return float64(maxSum) / float64(k)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
#hard
Задача: 644. Maximum Average Subarray II

Вам дан целочисленный массив nums, состоящий из n элементов, и целое число k. Найдите смежный подмассив, длина которого больше или равна k и который имеет максимальное среднее значение, и верните это значение. Принимается любой ответ с погрешностью вычислений менее 10-5.

Пример:
Input: nums = [1,12,-5,-6,50,3], k = 4
Output: 12.75000


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

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

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

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

😎 Решение:
func findMaxAverage(nums []int, k int) float64 {
n := len(nums)
currSum := 0
for i := 0; i < k; i++ {
currSum += nums[i]
}
maxSum := currSum
for i := k; i < n; i++ {
currSum += nums[i] - nums[i - k]
if currSum > maxSum {
maxSum = currSum
}
}
return float64(maxSum) / float64(k)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#easy
Задача: 645. Set Mismatch

У вас есть набор целых чисел s, который изначально содержит все числа от 1 до n. К сожалению, из-за какой-то ошибки одно из чисел в s продублировалось в другое число в наборе, что привело к повторению одного числа и потере другого. Вам дан целочисленный массив nums, представляющий состояние данных в этом наборе после ошибки. Найдите число, которое встречается дважды, и число, которое отсутствует, и верните их в виде массива.

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


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

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

2⃣Определите отсутствующее число, используя сумму чисел от 1 до n и текущую сумму массива.

3⃣Верните дублированное и отсутствующее числа в виде массива.

😎 Решение:
func findErrorNums(nums []int) []int {
numSet := make(map[int]bool)
duplicate := -1
n := len(nums)
for _, num := range nums {
if numSet[num] {
duplicate = num
}
numSet[num] = true
}
sum := 0
for num := range numSet {
sum += num
}
missing := (n * (n + 1)) / 2 - sum
return []int{duplicate, missing}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
#medium
Задача: 646. Maximum Length of Pair Chain

Вам дан массив из n пар, где pairs[i] = [lefti, righti] и lefti < righti. Пара p2 = [c, d] следует за парой p1 = [a, b], если b < c. Таким образом можно построить цепочку пар. Верните самую длинную цепочку, которую можно составить. Вам не нужно использовать все заданные интервалы. Вы можете выбирать пары в любом порядке.

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


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

1⃣Отсортируйте пары по второму элементу каждой пары (righti).

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

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

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

func findLongestChain(pairs [][]int) int {
sort.Slice(pairs, func(i, j int) bool {
return pairs[i][1] < pairs[j][1]
})
currentEnd := -int(^uint(0) >> 1) // Equivalent to -Infinity
count := 0
for _, pair := range pairs {
if currentEnd < pair[0] {
currentEnd = pair[1]
count++
}
}
return count
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#hard
Задача: 656. Coin Path

Вам дан целочисленный массив монет (1-индексированный) длины n и целое число maxJump. Вы можете перейти на любой индекс i массива coins, если coins[i] != -1 и вы должны заплатить coins[i] при посещении индекса i. Кроме того, если вы в данный момент находитесь на индексе i, вы можете перейти только на любой индекс i + k, где i + k <= n и k - значение в диапазоне [1, maxJump]. Изначально вы находитесь на индексе 1 (coins[1] не -1). Вы хотите найти путь, который достигнет индекса n с минимальной стоимостью. Верните целочисленный массив индексов, которые вы посетите в таком порядке, чтобы достичь индекса n с минимальной стоимостью. Если существует несколько путей с одинаковой стоимостью, верните лексикографически наименьший такой путь. Если невозможно достичь индекса n, возвращается пустой массив. Путь p1 = [Pa1, Pa2, ..., Pax] длины x лексикографически меньше, чем p2 = [Pb1, Pb2, ..., Pbx] длины y, если и только если при первом j, где Paj и Pbj отличаются, Paj < Pbj; если такого j нет, то x < y.

Пример:
Input: coins = [1,2,4,-1,2], maxJump = 2
Output: [1,3,5]


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

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

2⃣Храните путь до каждого индекса для отслеживания наименьшего лексикографического пути.

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

😎 Решение:
package main

import (
"container/heap"
"fmt"
"math"
"sort"
)

type Item struct {
cost, index int
}

type PriorityQueue []*Item

func (pq PriorityQueue) Len() int { return len(pq) }

func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].cost < pq[j].cost
}

func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
*pq = append(*pq, x.(*Item))
}

func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
return item
}

func minCostPath(coins []int, maxJump int) []int {
n := len(coins)
if coins[0] == -1 {
return []int{}
}

dp := make([]int, n)
for i := range dp {
dp[i] = math.MaxInt32
}
dp[0] = coins[0]
path := make([][]int, n)
for i := range path {
path[i] = []int{}
}
path[0] = []int{1}

pq := &PriorityQueue{&Item{cost: coins[0], index: 0}}
heap.Init(pq)

for pq.Len() > 0 {
current := heap.Pop(pq).(*Item)
currentCost, i := current.cost, current.index
if currentCost > dp[i] {
continue
}
for k := 1; k <= maxJump; k++ {
if i+k < n && coins[i+k] != -1 {
newCost := currentCost + coins[i+k]
newPath := append([]int{}, path[i]...)
newPath = append(newPath, i+k+1)
if newCost < dp[i+k] || (newCost == dp[i+k] && lexicographicalLess(newPath, path[i+k])) {
dp[i+k] = newCost
path[i+k] = newPath
heap.Push(pq, &Item{cost: newCost, index: i+k})
}
}
}
}

if dp[n-1] == math.MaxInt32 {
return []int{}
}
return path[n-1]
}

func lexicographicalLess(a, b []int) bool {
for i := range a {
if i >= len(b) {
return false
}
if a[i] != b[i] {
return a[i] < b[i]
}
}
return len(a) < len(b)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
#medium
Задача: 655. Print Binary Tree

Учитывая корень двоичного дерева, постройте строковую матрицу res с индексом 0 размером m x n, которая представляет собой форматированную раскладку дерева. Форматированная матрица должна быть построена по следующим правилам: высота дерева равна height, количество строк m должно быть равно height + 1. Количество столбцов n должно быть равно 2height+1 - 1. Поместите корневой узел в середину верхней строки (более формально, в позицию res[0][(n-1)/2]).
Для каждого узла, который был помещен в матрицу в позицию res[r][c], поместите его левого ребенка в res[r+1][c-2height-r-1], а правого - в res[r+1][c+2height-r-1]. Продолжайте этот процесс, пока не будут размещены все узлы дерева. Любые пустые ячейки должны содержать пустую строку "". Верните построенную матрицу res.

Пример:
Input: root = [1,2]
Output:
[["","1",""],
["2","",""]]


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

1⃣Найдите высоту дерева и определите размер матрицы (m x n).

2⃣Рекурсивно разместите узлы в матрице, начиная с корневого узла.

3⃣Верните заполненную матрицу.

😎 Решение:
package main

import (
"fmt"
"strconv"
"strings"
)

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

func findHeight(root *TreeNode) int {
if root == nil {
return -1
}
leftHeight := findHeight(root.Left)
rightHeight := findHeight(root.Right)
if leftHeight > rightHeight {
return 1 + leftHeight
}
return 1 + rightHeight
}

func fill(res [][]string, root *TreeNode, r, c, height int) {
if root == nil {
return
}
res[r][c] = strconv.Itoa(root.Val)
if root.Left != nil {
fill(res, root.Left, r+1, c-(1<<(height-r-1)), height)
}
if root.Right != nil {
fill(res, root.Right, r+1, c+(1<<(height-r-1)), height)
}
}

func printTree(root *TreeNode) [][]string {
height := findHeight(root)
m := height + 1
n := (1 << (height + 1)) - 1
res := make([][]string, m)
for i := range res {
res[i] = make([]string, n)
for j := range res[i] {
res[i][j] = ""
}
}
fill(res, root, 0, (n-1)/2, height)
return res
}

func main() {
root := &TreeNode{Val: 1, Left: &TreeNode{Val: 2}, Right: &TreeNode{Val: 3}}
result := printTree(root)
for _, row := range result {
fmt.Println(strings.Join(row, " "))
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#medium
Задача: 654. Maximum Binary Tree

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

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


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

1⃣Найдите максимальное значение в текущем подмассиве и создайте узел с этим значением.

2⃣Рекурсивно постройте левое поддерево для подмассива слева от максимального значения.

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

😎 Решение:
package main

import (
"fmt"
)

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

func constructMaximumBinaryTree(nums []int) *TreeNode {
return build(nums, 0, len(nums))
}

func build(nums []int, l, r int) *TreeNode {
if l == r {
return nil
}
maxIndex := max(nums, l, r)
root := &TreeNode{Val: nums[maxIndex]}
root.Left = build(nums, l, maxIndex)
root.Right = build(nums, maxIndex+1, r)
return root
}

func max(nums []int, l, r int) int {
maxIndex := l
for i := l + 1; i < r; i++ {
if nums[i] > nums[maxIndex] {
maxIndex = i
}
}
return maxIndex
}

func main() {
nums := []int{3, 2, 1, 6, 0, 5}
root := constructMaximumBinaryTree(nums)
fmt.Println(root)
}


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