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
#medium
Задача: 473. Matchsticks to Square

Дано целочисленный массив спичек, где matchsticks[i] — это длина i-й спички. Необходимо использовать все спички для создания одного квадрата. Нельзя ломать никакую спичку, но можно соединять их, при этом каждая спичка должна быть использована ровно один раз.

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

Пример:
Input: matchsticks = [1,1,2,2,2]
Output: true
Explanation: You can form a square with length 2, one side of the square came two sticks with length 1.


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

1⃣Определяем рекурсивную функцию, которая принимает текущий индекс обрабатываемой спички и количество сторон квадрата, которые уже полностью сформированы. Базовый случай для рекурсии: если все спички использованы и сформировано 4 стороны, возвращаем True.

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

3⃣Если какой-либо из рекурсивных вызовов возвращает True, возвращаем True, в противном случае возвращаем False.

😎 Решение:
package main

import (
"sort"
)

type Solution struct {
nums []int
sums []int
possibleSquareSide int
}

func Constructor() Solution {
return Solution{sums: make([]int, 4)}
}

func (this *Solution) dfs(index int) bool {
if index == len(this.nums) {
return this.sums[0] == this.sums[1] && this.sums[1] == this.sums[2] && this.sums[2] == this.sums[3]
}

element := this.nums[index]

for i := 0; i < 4; i++ {
if this.sums[i]+element <= this.possibleSquareSide {
this.sums[i] += element
if this.dfs(index + 1) {
return true
}
this.sums[i] -= element
}
}

return false
}

func (this *Solution) makesquare(nums []int) bool {
if len(nums) == 0 {
return false
}

perimeter := 0
for _, num := range nums {
perimeter += num
}

this.possibleSquareSide = perimeter / 4
if this.possibleSquareSide*4 != perimeter {
return false
}

this.nums = nums
sort.Sort(sort.Reverse(sort.IntSlice(this.nums)))
return this.dfs(0)
}

func main() {}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#medium
Задача: 227. Basic Calculator II

Дана строка s, представляющая выражение. Вычислите это выражение и верните его значение.

Целочисленное деление должно округляться к нулю.

Вы можете предположить, что данное выражение всегда является допустимым. Все промежуточные результаты будут находиться в диапазоне [-2^31, 2^31 - 1].

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

Пример:
Input: s = "3+2*2"
Output: 7


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

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

2⃣Если операция сложения (+) или вычитания (-), добавляем lastNumber к результату вместо того, чтобы помещать его в стек. Текущее значение currentNumber будет обновлено на lastNumber для следующей итерации.

3⃣Если операция умножения (*) или деления (/), вычисляем выражение lastNumber * currentNumber и обновляем lastNumber с результатом выражения. Это значение будет добавлено к результату после сканирования всей строки.

😎 Решение:
package main

import (
"strconv"
"unicode"
)

func calculate(s string) int {
length := len(s)
if length == 0 {
return 0
}
currentNumber, lastNumber, result := 0, 0, 0
sign := '+'

for i := 0; i < length; i++ {
currentChar := rune(s[i])
if unicode.IsDigit(currentChar) {
num, _ := strconv.Atoi(string(currentChar))
currentNumber = (currentNumber * 10) + num
}
if !unicode.IsDigit(currentChar) && !unicode.IsSpace(currentChar) || i == length-1 {
if sign == '+' || sign == '-' {
result += lastNumber
lastNumber = currentNumber
if sign == '-' {
lastNumber = -currentNumber
}
} else if sign == '*' {
lastNumber *= currentNumber
} else if sign == '/' {
lastNumber /= currentNumber
}
sign = currentChar
currentNumber = 0
}
}
result += lastNumber
return result
}


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

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

Диапазон [a,b] - это множество всех целых чисел от a до b (включительно).

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

Каждый диапазон [a,b] в списке должен быть представлен в формате:

"a->b" если a != b
"a" если a == b

Пример:
Input: nums = [0,1,2,4,5,7]
Output: ["0->2","4->5","7"]
Explanation: The ranges are:
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"


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

1⃣Создайте список строк ranges, который будет содержать решение задачи, и начните итерацию по всем элементам nums с указателем i = 0. Каждая итерация внешнего цикла представляет собой поиск одного диапазона. Для начала сохраните начало текущего диапазона в start = nums[i].

2⃣Проверьте, отличается ли следующий элемент в nums на индексе i + 1 от nums[i] на 1 или больше. Если следующий элемент отличается на 1, увеличьте i на 1, чтобы включить (i+1)-й элемент в этот диапазон и продолжайте проверку следующего элемента. Продолжайте добавлять элементы в этот диапазон, пока последовательные элементы отличаются на 1, используя цикл while для выполнения этой логики.

3⃣Если следующий элемент отличается более чем на 1 или если все элементы в nums уже обработаны, проверьте, равен ли start значению nums[i]. Если start == nums[i], добавьте только start как строку в ranges, так как у нас есть только один элемент в этом диапазоне. Если start != nums[i], добавьте строку start->nums[i] в ranges. Увеличьте i на 1, чтобы начать новый диапазон.

😎 Решение:
package main

import (
"fmt"
"strconv"
)

func summaryRanges(nums []int) []string {
ranges := []string{}
i := 0
for i < len(nums) {
start := nums[i]
for i+1 < len(nums) && nums[i]+1 == nums[i+1] {
i++
}
if start != nums[i] {
ranges = append(ranges, strconv.Itoa(start)+"->"+strconv.Itoa(nums[i]))
} else {
ranges = append(ranges, strconv.Itoa(start))
}
i++
}
return ranges
}

func main() {
nums := []int{0, 1, 2, 4, 5, 7}
fmt.Println(summaryRanges(nums))
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1🤔1
#medium
Задача: 474. Ones and Zeroes

Дан массив двоичных строк strs и два целых числа m и n.

Верните размер наибольшего подмножества strs, такого что в подмножестве содержится не более m нулей и n единиц.

Множество x является подмножеством множества y, если все элементы множества x также являются элементами множества y.

Пример:
Input: strs = ["10","0001","111001","1","0"], m = 5, n = 3
Output: 4
Explanation: The largest subset with at most 5 0's and 3 1's is {"10", "0001", "1", "0"}, so the answer is 4.
Other valid but smaller subsets include {"0001", "1"} and {"10", "1", "0"}.
{"111001"} is an invalid subset because it contains 4 1's, greater than the maximum of 3.


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

1⃣Рассматриваем все возможные подмножества, прерывая цикл, если количество нулей превышает m или количество единиц превышает n.

2⃣Считаем количество нулей и единиц в каждом подмножестве.

3⃣Выбираем наибольшее подмножество, соответствующее условиям, и возвращаем его размер.

😎 Решение:
package main

import (
"fmt"
)

type Solution struct{}

func (s *Solution) findMaxForm(strs []string, m int, n int) int {
maxlen := 0
for i := 0; i < (1 << len(strs)); i++ {
zeroes, ones, length := 0, 0, 0
for j := 0; j < 32; j++ {
if (i & (1 << j)) != 0 {
count := s.countZeroesOnes(strs[j])
zeroes += count[0]
ones += count[1]
if zeroes > m || ones > n {
break
}
length++
}
}
if zeroes <= m && ones <= n {
maxlen = max(maxlen, length)
}
}
return maxlen
}

func (s *Solution) countZeroesOnes(str string) [2]int {
count := [2]int{}
for _, char := range str {
count[char-'0']++
}
return count
}

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

func main() {
sol := Solution{}
fmt.Println(sol.findMaxForm([]string{"10", "0001", "111001", "1", "0"}, 5, 3))
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤔1
#medium
Задача: 229. Majority Element II

Дан массив целых чисел размера n, найдите все элементы, которые встречаются более ⌊ n/3 ⌋ раз.

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


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

1⃣Поиск кандидатов: Пройдите через массив, используя алгоритм Бойера-Мура для поиска двух потенциальных кандидатов, которые могут встречаться более ⌊ n/3 ⌋ раз. Поддерживайте два счётчика и двух кандидатов. Если текущий элемент равен одному из кандидатов, увеличьте соответствующий счётчик. Если счётчик равен нулю, установите текущий элемент как кандидата и установите счётчик в 1. Если текущий элемент не совпадает ни с одним из кандидатов, уменьшите оба счётчика.

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

3⃣Проверка порога: Проверьте, превышает ли количество появлений каждого кандидата порог ⌊ n/3 ⌋. Если да, добавьте кандидата в результат.

😎 Решение:
package main

func majorityElement(nums []int) []int {
count1, count2 := 0, 0
var candidate1, candidate2 *int

for _, n := range nums {
if candidate1 != nil && *candidate1 == n {
count1++
} else if candidate2 != nil && *candidate2 == n {
count2++
} else if count1 == 0 {
candidate1 = &n
count1 = 1
} else if count2 == 0 {
candidate2 = &n


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#hard
Задача: 329. Longest Increasing Path in a Matrix

Дана матрица целых чисел размером m x n. Верните длину самого длинного возрастающего пути в матрице.
Из каждой ячейки можно перемещаться в четырех направлениях: влево, вправо, вверх или вниз. Перемещение по диагонали или выход за границы матрицы (т.е. замкнутые переходы) не допускается.

Пример:
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].


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

1⃣Инициализация и создание матрицы:
Инициализируйте размеры матрицы m и n. Создайте матрицу matrix с добавленными границами (нулевыми значениями) вокруг исходной матрицы, чтобы избежать выхода за пределы при обработке.
Рассчитайте количество исходящих связей (outdegrees) для каждой клетки и сохраните их в outdegree.

2⃣Поиск начальных листьев:
Найдите все клетки с нулевыми исходящими связями и добавьте их в список leaves. Эти клетки будут начальной точкой для "слоевого удаления".

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

😎 Решение:
var dir = [][]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}

func longestIncreasingPath(matrix [][]int) int {
m := len(matrix)
if m == 0 {
return 0
}
n := len(matrix[0])
outdegree := make([][]int, m+2)
newMatrix := make([][]int, m+2)
for i := range outdegree {
outdegree[i] = make([]int, n+2)
newMatrix[i] = make([]int, n+2)
}

for i := 0; i < m; i++ {
copy(newMatrix[i+1][1:], matrix[i])
}

for i := 1; i <= m; i++ {
for j := 1; j <= n; j++ {
for _, d := range dir {
if newMatrix[i][j] < newMatrix[i+d[0]][j+d[1]] {
outdegree[i][j]++
}
}
}
}

var leaves [][]int
for i := 1; i <= m; i++ {
for j := 1; j <= n; j++ {
if outdegree[i][j] == 0 {
leaves = append(leaves, []int{i, j})
}
}
}

height := 0
for len(leaves) > 0 {
height++
var newLeaves [][]int
for _, node := range leaves {
for _, d := range dir {
x, y := node[0]+d[0], node[1]+d[1]
if newMatrix[node[0]][node[1]] > newMatrix[x][y] {
outdegree[x][y]--
if outdegree[x][y] == 0 {
newLeaves = append(newLeaves, []int{x, y})
}
}
}
}
leaves = newLeaves
}

return height
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#medium
Задача: 230. Kth Smallest Element in a BST

Дан корень бинарного дерева поиска и целое число k. Верните k-ое по величине значение (нумерация с 1) среди всех значений узлов в дереве.

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


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

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

2⃣Извлечение узлов и проверка: Когда достигнете самого левого узла, извлеките узел из стека и уменьшите значение k на 1. Если k становится равным нулю, верните значение текущего узла, так как это и есть k-ое по величине значение.

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

😎 Решение:
func kthSmallest(root *TreeNode, k int) int {
stack := []*TreeNode{}

for {
for root != nil {
stack = append(stack, root)
root = root.Left
}
root = stack[len(stack)-1]
stack = stack[:len(stack)-1]
k--
if k == 0 {
return root.Val
}
root = root.Right
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#easy
Задача: 231. Power of Two

Дано целое число n, верните true, если оно является степенью двойки. В противном случае верните false.

Целое число n является степенью двойки, если существует целое число x, такое что n == 2^x.

Пример:
Input: n = 1
Output: true
Explanation: 2^0 = 1


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

1⃣Проверка на ноль: Если n равно нулю, верните false, так как ноль не является степенью двойки.

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

3⃣Побитовая проверка: Используйте побитовую операцию, чтобы проверить, является ли число степенью двойки. Число является степенью двойки, если результат выражения (x & (-x)) равен x.

😎 Решение:
func isPowerOfTwo(n int) bool {
if n == 0 {
return false
}
x := int64(n)
return (x & -x) == x
}


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

Реализуйте очередь (FIFO) с использованием только двух стеков. Реализованная очередь должна поддерживать все функции обычной очереди (push, peek, pop и empty).

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

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

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

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


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

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

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

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

😎 Решение:
type MyQueue struct {
s1, s2 []int
front int
}

func Constructor() MyQueue {
return MyQueue{}
}

func (this *MyQueue) Push(x int) {
if len(this.s1) == 0 {
this.front = x
}
for len(this.s1) > 0 {
this.s2 = append(this.s2, this.s1[len(this.s1)-1])
this.s1 = this.s1[:len(this.s1)-1]
}
this.s2 = append(this.s2, x)
for len(this.s2) > 0 {
this.s1 = append(this.s1, this.s2[len(this.s2)-1])
this.s2 = this.s2[:len(this.s2)-1]
}
}

func (this *MyQueue) Pop() int {
res := this.s1[len(this.s1)-1]
this.s1 = this.s1[:len(this.s1)-1]
if len(this.s1) > 0 {
this.front = this.s1[len(this.s1)-1]
}
return res
}

func (this *MyQueue) Empty() bool {
return len(this.s1) == 0
}

func (this *MyQueue) Peek() int {
return this.front
}


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

Дополнение целого числа — это число, которое получается при замене всех 0 на 1 и всех 1 на 0 в его двоичном представлении.

Например, целое число 5 в двоичной системе — "101", и его дополнение — "010", что соответствует целому числу 2. Дано целое число num, верните его дополнение.

Пример:
Input: num = 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.


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

1⃣Вычислите длину в битах входного числа: l=⌊log 2 (num)⌋+1.

2⃣Постройте битовую маску из 1-битов длины l: bitmask=(1≪l)−1.

3⃣Верните результат операции XOR числа и битовой маски: num⊕bitmask num⊕bitmask.

😎 Решение:
package main

func findComplement(num int) int {
bitmask := num
bitmask |= (bitmask >> 1)
bitmask |= (bitmask >> 2)
bitmask |= (bitmask >> 4)
bitmask |= (bitmask >> 8)
bitmask |= (bitmask >> 16)
return bitmask ^ num
}

func main() {}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#hard
Задача: 233. Number of Digit One

Дано целое число n, посчитайте общее количество единиц, встречающихся во всех неотрицательных числах, меньших или равных n.

Пример:
Input: n = 13
Output: 6


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

1⃣Итерация по степеням 10: Итеративно увеличивайте значение i от 1 до n, увеличивая i в 10 раз на каждом шаге. Это позволяет анализировать каждую цифру числа n.

2⃣Подсчет групповых единиц: Для каждой итерации добавляйте (n / (i * 10)) * i к счетчику countr, что представляет собой количество единиц, встречающихся в группах размера i после каждого интервала (i * 10).

3⃣Добавление дополнительных единиц: Для каждой итерации добавляйте min(max((n % (i * 10)) - i + 1, 0), i) к счетчику countr, что представляет собой дополнительные единицы, зависящие от цифры на позиции i.

😎 Решение:
func countDigitOne(n int) int {
countr := 0
for i := int64(1); i <= int64(n); i *= 10 {
divider := i * 10
countr += int(int64(n)/divider)*int(i) + int(min(max(int64(n)%divider-i+1, 0), i))
}
return countr
}

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

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


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#medium
Задача: 331. Verify Preorder Serialization of a Binary Tree

Один из способов сериализации бинарного дерева — использование обхода в порядке предварительного прохода (preorder traversal). Когда мы встречаем ненулевой узел, мы записываем значение узла. Если это нулевой узел, мы записываем его с использованием специального значения, такого как '#'.

Дана строка, содержащая значения, разделенные запятыми, представляющие предварительный обход дерева (preorder). Верните true, если это правильная сериализация предварительного обхода бинарного дерева.

Гарантируется, что каждое значение в строке, разделенное запятыми, должно быть либо целым числом, либо символом '#', представляющим нулевой указатель.
Вы можете предположить, что формат ввода всегда действителен.
Например, он никогда не может содержать две последовательные запятые, такие как "1,,3".
Примечание: Вам не разрешено восстанавливать дерево.

Пример:
Input: preorder = "9,3,4,#,#,1,#,#,2,#,6,#,#"
Output: true


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

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

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

3⃣Проверка завершения:
После итерации по всем элементам проверьте, равно ли количество слотов 0. Если да, верните true, в противном случае false.

😎 Решение:
func isValidSerialization(preorder string) bool {
slots := 1
nodes := strings.Split(preorder, ",")

for _, node := range nodes {
slots--
if slots < 0 {
return false
}
if node != "#" {
slots += 2
}
}

return slots == 0
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤔1
#easy
Задача: 234. Palindrome Linked List

Дан головной элемент односвязного списка. Верните true, если список является палиндромом, и false в противном случае.

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


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

1⃣Копирование односвязного списка в массив: Итеративно пройдите по односвязному списку, добавляя каждое значение в массив. Для этого используйте переменную currentNode, указывающую на текущий узел. На каждой итерации добавляйте currentNode.val в массив и обновляйте currentNode, чтобы он указывал на currentNode.next. Остановите цикл, когда currentNode укажет на null.

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

3⃣Сравнение значений: Помните, что необходимо сравнивать значения узлов, а не сами узлы. Используйте node_1.val == node_2.val для сравнения значений узлов. Сравнение узлов как объектов node_1 == node_2 не даст ожидаемого результата.

😎 Решение:
func isPalindrome(head *ListNode) bool {
vals := []int{}
currentNode := head

for currentNode != nil {
vals = append(vals, currentNode.Val)
currentNode = currentNode.Next
}

front := 0
back := len(vals) - 1
for front < back {
if vals[front] != vals[back] {
return false
}
front++
back--
}
return true
}


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

Спроектируйте и реализуйте структуру данных для кеша с наименьшим количеством использования (Least Frequently Used, LFU).

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

LFUCache(int capacity): Инициализирует объект с указанной вместимостью структуры данных.
int get(int key): Возвращает значение ключа, если ключ существует в кеше. В противном случае возвращает -1.
void put(int key, int value): Обновляет значение ключа, если он уже присутствует, или вставляет ключ, если его еще нет. Когда кеш достигает своей вместимости, он должен аннулировать и удалить ключ, используемый наименее часто, перед вставкой нового элемента. В этой задаче, если имеется несколько ключей с одинаковой частотой использования, аннулируется наименее недавно использованный ключ.
Чтобы определить наименее часто используемый ключ, для каждого ключа в кеше поддерживается счетчик использования. Ключ с наименьшим счетчиком использования является наименее часто используемым ключом.
Когда ключ впервые вставляется в кеш, его счетчик использования устанавливается на 1 (из-за операции put). Счетчик использования для ключа в кеше увеличивается при вызове операции get или put для этого ключа.

Функции get и put должны иметь среднюю временную сложность O(1).

Пример:
Input
["LFUCache", "put", "put", "get", "put", "get", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [3], [4, 4], [1], [3], [4]]
Output
[null, null, null, 1, null, -1, 3, null, -1, 3, 4]


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

1⃣insert(int key, int frequency, int value):
Вставить пару частота-значение в cache с заданным ключом.
Получить LinkedHashSet, соответствующий данной частоте (по умолчанию пустой Set), и вставить в него ключ.

2⃣int get(int key):
Если ключа нет в кеше, вернуть -1.
Получить частоту и значение из кеша.
Удалить ключ из LinkedHashSet, связанного с частотой.
Если minf == frequency и LinkedHashSet пуст, увеличить minf на 1 и удалить запись частоты из frequencies.
Вызвать insert(key, frequency + 1, value).
Вернуть значение.

3⃣void put(int key, int value):
Если capacity <= 0, выйти.
Если ключ существует, обновить значение и вызвать get(key).
Если размер кеша равен capacity, удалить первый элемент из LinkedHashSet, связанного с minf, и из кеша.
Установить minf в 1.
Вызвать insert(key, 1, value).

😎 Решение:
package main
type LFUCache struct {
cache map[int][2]int
frequencies map[int][]int
capacity int
minf int
}
func Constructor(capacity int) LFUCache {
return LFUCache{
cache: make(map[int][2]int),
frequencies: make(map[int][]int),
capacity: capacity,
}
}
func (c *LFUCache) insert(key, freq, value int) {
c.frequencies[freq] = append(c.frequencies[freq], key)
c.cache[key] = [2]int{freq, value}
}
func (c *LFUCache) Get(key int) int {
if val, found := c.cache[key]; !found {
return -1
} else {
freq, value := val[0], val[1]
c.frequencies[freq] = removeKey(c.frequencies[freq], key)
if len(c.frequencies[freq]) == 0 {
delete(c.frequencies, freq)
if c.minf == freq {
c.minf++
}
}
c.insert(key, freq+1, value)
return value
}
}
func (c *LFUCache) Put(key int, value int) {
if c.capacity <= 0 {
return
}
if val, found := c.cache[key]; found {
c.cache[key] = [2]int{val[0], value}
c.Get(key)
return
}
if len(c.cache) == c.capacity {
minFreqKeys := c.frequencies[c.minf]
delete(c.cache, minFreqKeys[0])
c.frequencies[c.minf] = minFreqKeys[1:]
if len(c.frequencies[c.minf]) == 0 {
delete(c.frequencies, c.minf)
}
}
c.minf = 1
c.insert(key, 1, value)
}
func removeKey(slice []int, key int) []int {
for i, v := range slice {
if v == key {
return append(slice[:i], slice[i+1:]...)
}
}
return slice
}


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

Дано целое число length и массив updates, где updates[i] = [startIdxi, endIdxi, inci].

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

Верните arr после применения всех обновлений.

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


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

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

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

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

😎 Решение:
fun getModifiedArray(length: Int, updates: Array<IntArray>): IntArray {
val result = IntArray(length)

for (update in updates) {
val start = update[0]
val end = update[1]
val `val` = update[2]
result[start] += `val`
if (end + 1 < length) {
result[end + 1] -= `val`
}
}

for (i in 1 until length) {
result[i] += result[i - 1]
}

return result
}


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

Дано целое число length и массив updates, где updates[i] = [startIdxi, endIdxi, inci].

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

Верните arr после применения всех обновлений.

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


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

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

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

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

😎 Решение:
func getModifiedArray(length int, updates [][]int) []int {
result := make([]int, length)

for _, update := range updates {
start, end, val := update[0], update[1], update[2]
result[start] += val
if end+1 < length {
result[end+1] -= val
}
}

for i := 1; i < length; i++ {
result[i] += result[i-1]
}

return result
}


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

Даны два целых числа 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
#medium
Задача: 372. Super Pow

Ваша задача — вычислить а^b mod 1337, где a - положительное число, а b - чрезвычайно большое положительное целое число, заданное в виде массива.

Пример:
Input: a = 2, b = [3]
Output: 8


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

1⃣Разделите задачу на более мелкие задачи: вычислите a^b mod 1337, используя свойства модульной арифметики и степенной функции. Разделите большой показатель b на меньшие части, чтобы обрабатывать их по очереди.

2⃣Используйте метод быстрого возведения в степень (pow) для эффективного вычисления больших степеней с модулем 1337.

3⃣Объедините результаты для каждой части показателя b, используя свойства модульной арифметики: (a^b) % 1337 = ((a^(b1)) % 1337 * (a^(b2)) % 1337 * ...) % 1337.

😎 Решение:
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
💊2🤔1
#easy
Задача: 461. Hamming Distance

Расстояние Хэмминга между двумя целыми числами — это количество позиций, в которых соответствующие биты различны.

Даны два целых числа x и y, верните расстояние Хэмминга между ними.

Пример:
Input: x = 3, y = 1
Output: 1


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

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

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

3⃣Пошаговый подсчет битов:
Выполните побитовое XOR между x и y.
Инициализируйте счетчик bitCount = 0.
Пока число не равно нулю:
Если текущий бит равен 1, увеличьте bitCount.
Сдвиньте число вправо на один бит.
Возвращайте bitCount.

😎 Решение:
package main

import (
"math/bits"
)

func hammingDistance(x int, y int) int {
return bits.OnesCount(uint(x ^ y))
}


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

Вам дан список авиабилетов, где tickets[i] = [fromi, toi] представляют собой аэропорты отправления и прибытия одного рейса. Восстановите маршрут в порядке следования и верните его.

Все билеты принадлежат человеку, который вылетает из "JFK", поэтому маршрут должен начинаться с "JFK". Если существует несколько возможных маршрутов, вы должны вернуть маршрут, который имеет наименьший лексикографический порядок при чтении как одна строка.
Например, маршрут ["JFK", "LGA"] имеет меньший лексикографический порядок, чем ["JFK", "LGB"].
Вы можете предположить, что все билеты формируют хотя бы один действительный маршрут. Вы должны использовать все билеты один раз и только один раз.

Пример:
Input: tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
Output: ["JFK","MUC","LHR","SFO","SJC"]


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

1⃣Построение графа и сортировка:
Создайте граф flightMap, где ключи - это аэропорты отправления, а значения - это списки аэропортов прибытия.
Пройдите по всем билетам и заполните flightMap соответствующими значениями.
Отсортируйте списки аэропортов прибытия в лексикографическом порядке.

2⃣Пост-упорядоченный обход (DFS):
Создайте функцию DFS, которая будет рекурсивно проходить по всем ребрам (рейсам), начиная с аэропорта "JFK".
Во время обхода удаляйте использованные рейсы из графа, чтобы не проходить по ним повторно.

3⃣Формирование маршрута:
По мере завершения обхода добавляйте текущий аэропорт в начало списка результата.
После завершения DFS верните сформированный маршрут.

😎 Решение:
func findItinerary(tickets [][]string) []string {
flightMap := make(map[string][]string)
result := []string{}

for _, ticket := range tickets {
flightMap[ticket[0]] = append(flightMap[ticket[0]], ticket[1])
}

for key := range flightMap {
sort.Strings(flightMap[key])
}

var dfs func(string)
dfs = func(origin string) {
for len(flightMap[origin]) > 0 {
nextDest := flightMap[origin][0]
flightMap[origin] = flightMap[origin][1:]
dfs(nextDest)
}
result = append([]string{origin}, result...)
}

dfs("JFK")
return result
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
#medium
Задача: 333. Largest BST Subtree

Дан корень бинарного дерева, найдите самое большое поддерево, которое также является деревом бинарного поиска (BST), где "самое большое" означает поддерево с наибольшим количеством узлов.

Дерево бинарного поиска (BST) — это дерево, в котором все узлы соблюдают следующие свойства:
Значения в левом поддереве меньше значения их родительского (корневого) узла.
Значения в правом поддереве больше значения их родительского (корневого) узла.
Примечание: Поддерево должно включать всех своих потомков.

Пример:
Input: root = [10,5,15,1,8,null,7]
Output: 3
Explanation: The Largest BST Subtree in this case is the highlighted one. The return value is the subtree's size, which is 3.


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

1⃣Пост-упорядоченный обход дерева:
Обходите каждую ноду дерева в пост-упорядоченном порядке (left-right-root). Это позволит гарантировать, что обе поддеревья ноды уже проверены на соответствие критериям BST перед проверкой самой ноды.

2⃣Проверка условий BST для каждой ноды:
Для каждой ноды определите минимальное и максимальное значения в её левом и правом поддеревьях. Проверьте, удовлетворяет ли текущее поддерево условиям BST:
- значение текущей ноды должно быть больше максимального значения в левом поддереве.
- значение текущей ноды должно быть меньше минимального значения в правом поддереве.
Если условия выполняются, вычислите размер текущего поддерева как сумму размеров левого и правого поддеревьев плюс 1 (для текущей ноды).

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

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

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

type NodeValue struct {
minNode, maxNode, maxSize int
}

func largestBSTSubtreeHelper(root *TreeNode) NodeValue {
if root == nil {
return NodeValue{math.MaxInt64, math.MinInt64, 0}
}

left := largestBSTSubtreeHelper(root.Left)
right := largestBSTSubtreeHelper(root.Right)

if left.maxNode < root.Val && root.Val < right.minNode {
return NodeValue{min(root.Val, left.minNode), max(root.Val, right.maxNode),
left.maxSize + right.maxSize + 1}
}

return NodeValue{math.MinInt64, math.MaxInt64, max(left.maxSize, right.maxSize)}
}

func largestBSTSubtree(root *TreeNode) int {
return largestBSTSubtreeHelper(root).maxSize
}

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

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


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