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
#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
#hard
Задача: 679. 24 Game

Дан массив целых чисел cards длиной 4. У вас есть четыре карты, каждая из которых содержит число в диапазоне от 1 до 9. Вам нужно расположить числа на этих картах в математическом выражении, используя операторы ['+', '-', '*', '/'] и скобки '(' и ')' так, чтобы получить значение 24.

Вы ограничены следующими правилами:

Оператор деления '/' представляет собой реальное деление, а не целочисленное деление.
Например, 4 / (1 - 2 / 3) = 4 / (1 / 3) = 12.
Каждая операция выполняется между двумя числами. В частности, мы не можем использовать '-' как унарный оператор.
Например, если cards = [1, 1, 1, 1], выражение "-1 - 1 - 1 - 1" не допускается.
Вы не можете объединять числа вместе.
Например, если cards = [1, 2, 1, 2], выражение "12 + 12" недопустимо.
Вернуть true, если вы можете получить такое выражение, которое оценивается в 24, и false в противном случае.

Пример:
Input: cards = [4,1,8,7]
Output: true
Explanation: (8-4) * (7-1) = 24


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

1⃣Создайте функцию generatePossibleResults(a, b), которая возвращает массив результатов всех возможных математических операций над двумя числами.

2⃣ Создайте функцию checkIfResultReached(list), чтобы проверить, можем ли мы достичь результата 24, используя текущий массив list. Сначала проверьте базовые условия: если размер массива равен 1, верните true, если результат равен 24, иначе верните false.

3⃣Если размер массива больше 1, выберите любые два числа из списка, выполните все математические операции над ними, создайте новый список с обновленными элементами и снова вызовите рекурсивную функцию с этим новым списком. Если ни одна комбинация не приводит к результату 24, верните false. Вызовите checkIfResultReached с исходным списком карт.

😎 Решение:
package main

import (
"math"
)

type Solution struct{}

func (s *Solution) generatePossibleResults(a, b float64) []float64 {
res := []float64{a + b, a - b, b - a, a * b}
if a != 0 {
res = append(res, b/a)
}
if b != 0 {
res = append(res, a/b)
}
return res
}

func (s *Solution) checkIfResultReached(list []float64) bool {
if len(list) == 1 {
return math.Abs(list[0]-24) <= 0.1
}

for i := 0; i < len(list); i++ {
for j := i + 1; j < len(list); j++ {
newList := make([]float64, 0, len(list)-1)
for k := 0; k < len(list); k++ {
if k != i && k != j {
newList = append(newList, list[k])
}
}
for _, res := range s.generatePossibleResults(list[i], list[j]) {
newList = append(newList, res)
if s.checkIfResultReached(newList) {
return true
}
newList = newList[:len(newList)-1]
}
}
}
return false
}

func (s *Solution) judgePoint24(cards []int) bool {
list := make([]float64, len(cards))
for i, card := range cards {
list[i] = float64(card)
}
return s.checkIfResultReached(list)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#hard
Задача: 363. Max Sum of Rectangle No Larger Than K

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

Гарантируется, что будет прямоугольник с суммой, не превышающей k.

Пример:
Input: matrix = [[1,0,1],[0,-2,3]], k = 2
Output: 2
Explanation: Because the sum of the blue rectangle [[0, 1], [-2, 3]] is 2, and 2 is the max number no larger than k (k = 2).


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

1⃣Создать вспомогательную функцию updateResult, которая будет находить максимальную сумму подмассива в одномерном массиве, не превышающую k.

2⃣Преобразовать каждую подматрицу в одномерный массив и применить к ней функцию updateResult.

3⃣Вернуть максимальную найденную сумму.

😎 Решение:
package main

import (
"math"
"sort"
)

type Solution struct {
result int
}

func Constructor() Solution {
return Solution{result: math.MinInt32}
}

func (this *Solution) updateResult(nums []int, k int) {
sum := 0
sortedSum := []int{0}

for _, num := range nums {
sum += num
idx := sort.Search(len(sortedSum), func(i int) bool { return sortedSum[i] >= sum-k })
if idx < len(sortedSum) {
this.result = int(math.Max(float64(this.result), float64(sum-sortedSum[idx])))
}
sortedSum = append(sortedSum, sum)
sort.Ints(sortedSum)
}
}

func (this *Solution) maxSumSubmatrix(matrix [][]int, k int) int {
rows := len(matrix)
cols := len(matrix[0])

for i := 0; i < rows; i++ {
rowSum := make([]int, cols)
for row := i; row < rows; row++ {
for col := 0; col < cols; col++ {
rowSum[col] += matrix[row][col]
}
this.updateResult(rowSum, k)
if this.result == k {
return this.result
}
}
}
return this.result
}


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


Дан целочисленный массив nums, вернуть количество всех арифметических подпоследовательностей nums.

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

Например, [1, 3, 5, 7, 9], [7, 7, 7, 7] и [3, -1, -5, -9] являются арифметическими последовательностями.
Например, [1, 1, 2, 5, 7] не является арифметической последовательностью.
Подпоследовательность массива - это последовательность, которая может быть образована путем удаления некоторых элементов (возможно, ни одного) из массива.

Например, [2, 5, 10] является подпоследовательностью [1, 2, 1, 2, 4, 1, 5, 10].
Тестовые случаи сгенерированы таким образом, что ответ помещается в 32-битное целое число.

Пример:
Input: nums = [2,4,6,8,10]
Output: 7
Explanation: All arithmetic subsequence slices are:
[2,4,6]
[4,6,8]
[6,8,10]
[2,4,6,8]
[4,6,8,10]
[2,4,6,8,10]
[2,6,10]


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

1⃣Мы можем использовать поиск в глубину (DFS) для генерации всех подпоследовательностей.

2⃣Мы можем проверить, является ли подпоследовательность арифметической, согласно ее определению.

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

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

func (sol *Solution) dfs(dep int, A []int, cur []int64) {
if dep == sol.n {
if len(cur) < 3 {
return
}
for i := 1; i < len(cur); i++ {
if cur[i]-cur[i-1] != cur[1]-cur[0] {
return
}
}
sol.ans++
return
}
sol.dfs(dep+1, A, cur)
cur = append(cur, int64(A[dep]))
sol.dfs(dep+1, A, cur)
cur = cur[:len(cur)-1]
}

func numberOfArithmeticSlices(A []int) int {
sol := Solution{n: len(A), ans: 0}
sol.dfs(0, A, []int64{})
return sol.ans
}


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

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

Фрагмент кода считается корректным, если соблюдаются все следующие правила:
Код должен быть заключен в корректный закрытый тег. В противном случае код некорректен.
Закрытый тег (не обязательно корректный) имеет точно следующий формат: <TAG_NAME>TAG_CONTENT</TAG_NAME>. Среди них <TAG_NAME> — это начальный тег, а </TAG_NAME> — конечный тег. TAG_NAME в начальном и конечном тегах должен быть одинаковым. Закрытый тег корректен, если и только если TAG_NAME и TAG_CONTENT корректны.
Корректное TAG_NAME содержит только заглавные буквы и имеет длину в диапазоне [1, 9]. В противном случае TAG_NAME некорректен.
Корректное TAG_CONTENT может содержать другие корректные закрытые теги, cdata и любые символы (см. примечание 1), КРОМЕ неподходящих <, неподходящих начальных и конечных тегов, и неподходящих или закрытых тегов с некорректным TAG_NAME. В противном случае TAG_CONTENT некорректен.
Начальный тег неподходящий, если нет конечного тега с тем же TAG_NAME, и наоборот. Однако нужно также учитывать проблему несбалансированных тегов, когда они вложены.
< неподходящий, если не удается найти последующий >. И когда вы находите < или </, все последующие символы до следующего > должны быть разобраны как TAG_NAME (не обязательно корректный).
cdata имеет следующий формат: <![CDATA[CDATA_CONTENT]]>. Диапазон CDATA_CONTENT определяется как символы между <![CDATA[ и первым последующим ]]>.
CDATA_CONTENT может содержать любые символы. Функция cdata заключается в том, чтобы запретить валидатору разбирать CDATA_CONTENT, поэтому даже если в нем есть символы, которые могут быть разобраны как тег (корректный или некорректный), вы должны рассматривать их как обычные символы.

Пример:
Input: code = "<DIV>This is the first line <![CDATA[<div>]]></DIV>"
Output: true


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

1⃣Инициализируйте стек для отслеживания открытых тегов и флаг для определения наличия тегов. Используйте регулярное выражение для проверки корректности TAG_NAME, TAG_CONTENT и CDATA.

2⃣Пройдитесь по строке, проверяя каждый символ. Если встретите <, определите тип тега (начальный, конечный или CDATA). Обновите стек и индексы в зависимости от найденного типа.

3⃣В конце проверьте, что стек пуст (все теги корректно закрыты) и верните результат.

😎 Решение:
package main

import (
"regexp"
"strings"
)

type Solution struct {
stack []string
containsTag bool
}

func (s *Solution) isValidTagName(tag string, ending bool) bool {
if ending {
if len(s.stack) > 0 && s.stack[len(s.stack)-1] == tag {
s.stack = s.stack[:len(s.stack)-1]
} else {
return false
}
} else {
s.containsTag = true
s.stack = append(s.stack, tag)
}
return true
}

func (s *Solution) IsValid(code string) bool {
regex := "<[A-Z]{0,9}>([^<]*(<((\\/?[A-Z]{1,9}>)|(!\\[CDATA\\[(.*?)]]>)))?)*"
matched, _ := regexp.MatchString(regex, code)
if !matched {
return false
}

for i := 0; i < len(code); i++ {
ending := false
if len(s.stack) == 0 && s.containsTag {
return false
}
if code[i] == '<' {
if code[i+1] == '!' {
i = strings.Index(code[i+1:], "]]>") + i + 2
if i == -1 {
return false
}
continue
}
if code[i+1] == '/' {
i++
ending = true
}
closeIndex := strings.Index(code[i+1:], ">") + i + 1
if closeIndex == -1 || !s.isValidTagName(code[i+1:closeIndex], ending) {
return false
}
i = closeIndex
}
}
return len(s.stack) == 0
}


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

Вам дано целое число n и массив уникальных целых чисел blacklist. Разработайте алгоритм выбора случайного целого числа из диапазона [0, n - 1], не входящего в черный список. Любое целое число, находящееся в указанном диапазоне и не входящее в черный список, должно с равной вероятностью быть возвращено. Оптимизируйте алгоритм так, чтобы он минимизировал количество обращений к встроенной функции random вашего языка. Реализуйте класс Solution: Solution(int n, int[] blacklist) Инициализирует объект целым числом n и целым числом из черного списка blacklist. int pick() Возвращает случайное целое число в диапазоне [0, n - 1] и не входящее в черный список.

Пример:
Input
["Solution", "pick", "pick", "pick", "pick", "pick", "pick", "pick"]
[[7, [2, 3, 5]], [], [], [], [], [], [], []]
Output
[null, 0, 4, 1, 6, 1, 0, 4]


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

1⃣Создайте маппинг для чисел, входящих в черный список, чтобы сопоставить их с числами из диапазона [n - len(blacklist), n - 1], которые не входят в черный список.

2⃣Создайте массив для хранения возможных чисел для выбора, исключая числа из черного списка.

3⃣При каждом вызове функции pick() используйте встроенную функцию random для выбора случайного индекса из массива возможных чисел и возвращайте соответствующее значение.

😎 Решение:
package main

import (
"math/rand"
"time"
)

type Solution struct {
mapping map[int]int
bound int
}

func Constructor(n int, blacklist []int) Solution {
mapping := make(map[int]int)
bound := n - len(blacklist)
blackset := make(map[int]struct{})
for _, b := range blacklist {
blackset[b] = struct{}{}
}
whitelist := bound
for _, b := range blacklist {
if b < bound {
for {
if _, exists := blackset[whitelist]; !exists {
break
}
whitelist++
}
mapping[b] = whitelist
whitelist++
}
}
return Solution{mapping: mapping, bound: bound}
}

func (this *Solution) Pick() int {
r := rand.Intn(this.bound)
if mapped, exists := this.mapping[r]; exists {
return mapped
}
return r
}

func main() {
rand.Seed(time.Now().UnixNano())
}


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

Есть n пар, сидящих на 2n местах, расположенных в ряд, и они хотят держаться за руки.

Люди и места представлены массивом целых чисел row, где row[i] — это ID человека, сидящего на i-м месте. Пары пронумерованы по порядку: первая пара — (0, 1), вторая пара — (2, 3) и так далее, до последней пары — (2n - 2, 2n - 1).

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

Пример:
Input: row = [0,2,1,3]
Output: 1
Explanation: We only need to swap the second (row[1]) and third (row[2]) person.


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

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

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

3⃣Для каждого дивана с двумя возможностями (т.е. оба человека на диване несчастливы) мы попробуем первый вариант, найдем ответ как ans1, затем отменим наш ход и попробуем второй вариант, найдем связанный ответ как ans2, отменим наш ход и затем вернем наименьший ответ.

😎 Решение:
type Solution struct {
N int
pairs [][]int
}

func (s *Solution) minSwapsCouples(row []int) int {
s.N = len(row) / 2
s.pairs = make([][]int, s.N)
for i := 0; i < s.N; i++ {
s.pairs[i] = []int{row[2*i] / 2, row[2*i+1] / 2}
}
return s.solve(0)
}

func (s *Solution) swap(a, b, c, d int) {
t := s.pairs[a][b]
s.pairs[a][b] = s.pairs[c][d]
s.pairs[c][d] = t
}

func (s *Solution) solve(i int) int {
if i == s.N {
return 0
}
x, y := s.pairs[i][0], s.pairs[i][1]
if x == y {
return s.solve(i + 1)
}

var jx, kx, jy, ky int
for j := i + 1; j < s.N; j++ {
for k := 0; k <= 1; k++ {
if s.pairs[j][k] == x {
jx, kx = j, k
}
if s.pairs[j][k] == y {
jy, ky = j, k
}
}
}

s.swap(i, 1, jx, kx)
ans1 := 1 + s.solve(i+1)
s.swap(i, 1, jx, kx)

s.swap(i, 0, jy, ky)
ans2 := 1 + s.solve(i+1)
s.swap(i, 0, jy, ky)

if ans1 < ans2 {
return ans1
}
return ans2
}


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

Вам дана двоичная матричная сетка m x n. Остров - это группа 1 (представляющая сушу), соединенных в четырех направлениях (горизонтальном или вертикальном). Можно предположить, что все четыре края сетки окружены водой. Остров считается одинаковым с другим, если они имеют одинаковую форму, или имеют одинаковую форму после поворота (только на 90, 180 или 270 градусов) или отражения (влево/вправо или вверх/вниз). Верните количество разных островов.

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


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

1⃣Пройдите по каждому элементу матрицы, если найдена земля (1), выполните DFS для обнаружения всех связанных с этим островом земель и сохраните форму острова.

2⃣Нормализуйте форму острова, применив все возможные повороты и отражения, чтобы найти каноническую форму.

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

😎 Решение:
package main

import (
"sort"
"strconv"
"strings"
)

func numDistinctIslands2(grid [][]int) int {
uniqueIslands := make(map[string]struct{})

for i := 0; i < len(grid); i++ {
for j := 0; j < len(grid[0]); j++ {
if grid[i][j] == 1 {
shape := [][]int{}
dfs(grid, i, j, i, j, &shape)
uniqueIslands[normalize(shape)] = struct{}{}
}
}
}

return len(uniqueIslands)
}

func dfs(grid [][]int, i, j, baseI, baseJ int, shape *[][]int) {
if i < 0 || i >= len(grid) || j < 0 || j >= len(grid[0]) || grid[i][j] == 0 {
return
}
grid[i][j] = 0
*shape = append(*shape, []int{i - baseI, j - baseJ})
dfs(grid, i+1, j, baseI, baseJ, shape)
dfs(grid, i-1, j, baseI, baseJ, shape)
dfs(grid, i, j+1, baseI, baseJ, shape)
dfs(grid, i, j-1, baseI, baseJ, shape)
}

func normalize(shape [][]int) string {
shapes := make([][][]int, 8)
for i := range shapes {
shapes[i] = [][]int{}
}

for _, p := range shape {
x, y := p[0], p[1]
shapes[0] = append(shapes[0], []int{x, y})
shapes[1] = append(shapes[1], []int{x, -y})
shapes[2] = append(shapes[2], []int{-x, y})
shapes[3] = append(shapes[3], []int{-x, -y})
shapes[4] = append(shapes[4], []int{y, x})
shapes[5] = append(shapes[5], []int{y, -x})
shapes[6] = append(shapes[6], []int{-y, x})
shapes[7] = append(shapes[7], []int{-y, -x})
}

for i := range shapes {
sort.Slice(shapes[i], func(a, b int) bool {
if shapes[i][a][0] == shapes[i][b][0] {
return shapes[i][a][1] < shapes[i][b][1]
}
return shapes[i][a][0] < shapes[i][b][0]
})
}

minShape := shapeToString(shapes[0])
for _, s := range shapes {
shapeStr := shapeToString(s)
if shapeStr < minShape {
minShape = shapeStr
}
}

return minShape
}

func shapeToString(shape [][]int) string {
var sb strings.Builder
for _, p := range shape {
sb.WriteString(strconv.Itoa(p[0]))
sb.WriteString(",")
sb.WriteString(strconv.Itoa(p[1]))
sb.WriteString(";")
}
return sb.String()
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
#hard
Задача: 774. Minimize Max Distance to Gas Station

Вам дан массив целых чисел stations, который представляет позиции автозаправочных станций на оси x. Вам также дано целое число k.

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

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

Верните наименьшее возможное значение penalty(). Ответы, отличающиеся от фактического ответа не более чем на 10^-6, будут приняты.

Пример:
Input: stations = [1,2,3,4,5,6,7,8,9,10], k = 9
Output: 0.50000


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

1⃣Пусть i-й интервал равен deltas[i] = stations[i+1] - stations[i]. Мы хотим найти dp[n+1][k] как рекурсию. Мы можем поставить x автозаправочных станций в интервал n+1 с наилучшим расстоянием deltas[n+1] / (x+1), затем оставшиеся интервалы можно решить с ответом dp[n][k-x]. Ответ — это минимум среди всех x.

2⃣Из этой рекурсии мы можем разработать решение с использованием динамического программирования. Инициализируем двумерный массив dp, где dp[i][j] будет хранить минимальное возможное значение penalty при добавлении j автозаправочных станций на первые i интервалов.

3⃣Заполняем dp таблицу начиная с базового случая, когда нет добавленных станций. Затем для каждого интервала и количества добавленных станций вычисляем минимальное значение penalty, используя вышеописанную рекурсию. Итоговый ответ будет находиться в dp[n][k], где n — количество интервалов, а k — количество добавляемых станций.

😎 Решение:
func minmaxGasDist(stations []int, K int) float64 {
N := len(stations)
deltas := make([]float64, N-1)
for i := 0; i < N-1; i++ {
deltas[i] = float64(stations[i+1] - stations[i])
}

dp := make([][]float64, N-1)
for i := range dp {
dp[i] = make([]float64, K+1)
}
for i := 0; i <= K; i++ {
dp[0][i] = deltas[0] / float64(i+1)
}

for p := 1; p < N-1; p++ {
for k := 0; k <= K; k++ {
bns := 1e9
for x := 0; x <= k; x++ {
bns = math.Min(bns, math.Max(deltas[p] / float64(x+1), dp[p-1][k-x]))
}
dp[p][k] = bns
}
}

return dp[N-2][K]
}


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

Разработайте структуру данных max-стека, поддерживающую операции со стеком и поиск максимального элемента стека. Реализуйте класс MaxStack: MaxStack() Инициализирует объект стека. void push(int x) Вставляет элемент x в стек. int pop() Удаляет элемент на вершине стека и возвращает его. int top() Получает элемент на вершине стека без его удаления. int peekMax() Получает максимальный элемент в стеке без его удаления. int popMax() Получает максимальный элемент в стеке и удаляет его. Если максимальных элементов несколько, удалите только самый верхний. Вы должны придумать решение, которое поддерживает O(1) для каждого вызова вершины и O(logn) для каждого другого вызова.

Пример:
Input
["MaxStack", "push", "push", "push", "top", "popMax", "top", "peekMax", "pop", "top"]
[[], [5], [1], [5], [], [], [], [], [], []]
Output
[null, null, null, null, 5, 5, 1, 5, 1, 5]


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

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

2⃣Для операции push(x) добавьте элемент в оба стека: в основной стек и, если это необходимо, в стек максимумов. Для операции pop() удалите элемент из основного стека и, если этот элемент является текущим максимальным, удалите его и из стека максимумов. Для операции top() верните верхний элемент основного стека.

3⃣Для операции peekMax() верните верхний элемент стека максимумов. Для операции popMax() удалите и верните верхний элемент стека максимумов. Для этого временно извлеките элементы из основного стека до тех пор, пока не будет найден максимальный элемент, затем верните остальные элементы обратно.

😎 Решение:
package main

type MaxStack struct {
stack []int
maxStack []int
}

func Constructor() MaxStack {
return MaxStack{}
}

func (this *MaxStack) Push(x int) {
this.stack = append(this.stack, x)
if len(this.maxStack) == 0 || x >= this.maxStack[len(this.maxStack)-1] {
this.maxStack = append(this.maxStack, x)
}
}

func (this *MaxStack) Pop() int {
x := this.stack[len(this.stack)-1]
this.stack = this.stack[:len(this.stack)-1]
if x == this.maxStack[len(this.maxStack)-1] {
this.maxStack = this.maxStack[:len(this.maxStack)-1]
}
return x
}

func (this *MaxStack) Top() int {
return this.stack[len(this.stack)-1]
}

func (this *MaxStack) PeekMax() int {
return this.maxStack[len(this.maxStack)-1]
}

func (this *MaxStack) PopMax() int {
maxVal := this.maxStack[len(this.maxStack)-1]
this.maxStack = this.maxStack[:len(this.maxStack)-1]
buffer := []int{}
for this.stack[len(this.stack)-1] != maxVal {
buffer = append(buffer, this.stack[len(this.stack)-1])
this.stack = this.stack[:len(this.stack)-1]
}
this.stack = this.stack[:len(this.stack)-1]
for len(buffer) > 0 {
this.Push(buffer[len(buffer)-1])
buffer = buffer[:len(buffer)-1]
}
return maxVal
}


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