Задача: 535. Encode and Decode TinyURL
Сложность: medium
Спроектируйте класс для кодирования URL и декодирования короткого URL.
Нет ограничений на то, как ваш алгоритм кодирования/декодирования должен работать. Вам просто нужно убедиться, что URL может быть закодирован в короткий URL, а короткий URL может быть декодирован в исходный URL.
Реализуйте класс Solution:
Solution() Инициализирует объект системы.
String encode(String longUrl) Возвращает короткий URL для данного longUrl.
String decode(String shortUrl) Возвращает исходный длинный URL для данного shortUrl. Гарантируется, что данный shortUrl был закодирован тем же объектом.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация:
Создайте строку, содержащую все возможные символы (цифры и буквы), которые могут быть использованы для генерации кода.
Создайте хэш-таблицу для хранения соответствий коротких и длинных URL-адресов.
Создайте объект для генерации случайных чисел.
2⃣ Кодирование:
Сгенерируйте случайный 6-символьный код.
Если такой код уже существует в хэш-таблице, повторите генерацию.
Сохраните соответствие длинного URL и сгенерированного кода в хэш-таблице.
Верните полный короткий URL.
3⃣ Декодирование:
Удалите префикс короткого URL, чтобы получить код.
Используйте код для поиска длинного URL в хэш-таблице.
Верните длинный URL.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Спроектируйте класс для кодирования URL и декодирования короткого URL.
Нет ограничений на то, как ваш алгоритм кодирования/декодирования должен работать. Вам просто нужно убедиться, что URL может быть закодирован в короткий URL, а короткий URL может быть декодирован в исходный URL.
Реализуйте класс Solution:
Solution() Инициализирует объект системы.
String encode(String longUrl) Возвращает короткий URL для данного longUrl.
String decode(String shortUrl) Возвращает исходный длинный URL для данного shortUrl. Гарантируется, что данный shortUrl был закодирован тем же объектом.
Пример:
Input: url = "https://leetcode.com/problems/design-tinyurl"
Output: "https://leetcode.com/problems/design-tinyurl"
Explanation:
Solution obj = new Solution();
string tiny = obj.encode(url); // returns the encoded tiny url.
string ans = obj.decode(tiny); // returns the original url after decoding it.
Создайте строку, содержащую все возможные символы (цифры и буквы), которые могут быть использованы для генерации кода.
Создайте хэш-таблицу для хранения соответствий коротких и длинных URL-адресов.
Создайте объект для генерации случайных чисел.
Сгенерируйте случайный 6-символьный код.
Если такой код уже существует в хэш-таблице, повторите генерацию.
Сохраните соответствие длинного URL и сгенерированного кода в хэш-таблице.
Верните полный короткий URL.
Удалите префикс короткого URL, чтобы получить код.
Используйте код для поиска длинного URL в хэш-таблице.
Верните длинный URL.
package main
import (
"math/rand"
"time"
)
type Codec struct {
alphabet string
map map[string]string
}
func Constructor() Codec {
rand.Seed(time.Now().UnixNano())
return Codec{
alphabet: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
map: make(map[string]string),
}
}
func (this *Codec) getRand() string {
result := make([]byte, 6)
for i := 0; i < 6; i++ {
result[i] = this.alphabet[rand.Intn(62)]
}
return string(result)
}
func (this *Codec) Encode(longUrl string) string {
key := this.getRand()
for _, exists := this.map[key]; exists; {
key = this.getRand()
}
this.map[key] = longUrl
return "https://tinyurl.com/" + key
}
func (this *Codec) Decode(shortUrl string) string {
key := shortUrl[19:]
return this.map[key]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 314. Binary Tree Vertical Order Traversal
Сложность: medium
Дан корень бинарного дерева, верните вертикальный порядок обхода значений его узлов (т.е. сверху вниз, столбец за столбцом).
Если два узла находятся в одной строке и столбце, порядок должен быть слева направо.
Пример:
👨💻 Алгоритм:
1⃣ Создайте хэш-таблицу с именем columnTable для отслеживания результатов.
2⃣ Инициализируйте очередь, поместив в нее корневой узел вместе с его индексом столбца (0). Выполните обход в ширину (BFS), извлекая элементы из очереди. На каждой итерации извлекайте элемент, состоящий из узла и соответствующего индекса столбца. Если узел не пуст, добавьте его значение в columnTable. Затем поместите дочерние узлы с их индексами столбцов (т.е. column-1 и column+1) в очередь.
3⃣ После завершения BFS обхода получите хэш-таблицу, содержащую значения узлов, сгруппированные по индексам столбцов. Для каждой группы значений отсортируйте их по индексам строк. Отсортируйте хэш-таблицу по ключам (индексам столбцов) в порядке возрастания и верните результаты по столбцам.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан корень бинарного дерева, верните вертикальный порядок обхода значений его узлов (т.е. сверху вниз, столбец за столбцом).
Если два узла находятся в одной строке и столбце, порядок должен быть слева направо.
Пример:
Input: root = [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
package main
import (
"sort"
"container/list"
)
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func verticalOrder(root *TreeNode) [][]int {
var output [][]int
if root == nil {
return output
}
columnTable := map[int][]int{}
queue := list.New()
queue.PushBack([2]interface{}{root, 0})
for queue.Len() > 0 {
element := queue.Front()
queue.Remove(element)
pair := element.Value.([2]interface{})
node := pair[0].(*TreeNode)
column := pair[1].(int)
if node != nil {
columnTable[column] = append(columnTable[column], node.Val)
if node.Left != nil {
queue.PushBack([2]interface{}{node.Left, column - 1})
}
if node.Right != nil {
queue.PushBack([2]interface{}{node.Right, column + 1})
}
}
}
var sortedKeys []int
for key := range columnTable {
sortedKeys = append(sortedKeys, key)
}
sort.Ints(sortedKeys)
for _, key := range sortedKeys {
output = append(output, columnTable[key])
}
return output
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Задача: 256. Paint House
Сложность: medium
Есть ряд из n домов, где каждый дом можно покрасить в один из трёх цветов: красный, синий или зелёный. Стоимость покраски каждого дома в определённый цвет разная. Необходимо покрасить все дома так, чтобы никакие два соседних дома не были окрашены в один и тот же цвет.
Стоимость покраски каждого дома в определённый цвет представлена в виде матрицы стоимости n x 3.
Например, costs[0][0] — это стоимость покраски дома 0 в красный цвет; costs[1][2] — это стоимость покраски дома 1 в зелёный цвет и так далее...
Верните минимальную стоимость покраски всех домов.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте массив dp размера n x 3 для хранения минимальных затрат на покраску домов. Установите начальные значения для первого дома: dp[0][0] = costs[0][0], dp[0][1] = costs[0][1], dp[0][2] = costs[0][2].
2⃣ Для каждого дома i от 1 до n-1 обновите значения массива dp:
dp[i][0] = costs[i][0] + min(dp[i-1][1], dp[i-1][2])
dp[i][1] = costs[i][1] + min(dp[i-1][0], dp[i-1][2])
dp[i][2] = costs[i][2] + min(dp[i-1][0], dp[i-1][1])
3⃣ Верните минимальное значение из последней строки массива dp: min(dp[n-1][0], dp[n-1][1], dp[n-1][2]).
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Есть ряд из n домов, где каждый дом можно покрасить в один из трёх цветов: красный, синий или зелёный. Стоимость покраски каждого дома в определённый цвет разная. Необходимо покрасить все дома так, чтобы никакие два соседних дома не были окрашены в один и тот же цвет.
Стоимость покраски каждого дома в определённый цвет представлена в виде матрицы стоимости n x 3.
Например, costs[0][0] — это стоимость покраски дома 0 в красный цвет; costs[1][2] — это стоимость покраски дома 1 в зелёный цвет и так далее...
Верните минимальную стоимость покраски всех домов.
Пример:
Input: costs = [[17,2,17],[16,16,5],[14,3,19]]
Output: 10
Explanation: Paint house 0 into blue, paint house 1 into green, paint house 2 into blue.
Minimum cost: 2 + 5 + 3 = 10.
dp[i][0] = costs[i][0] + min(dp[i-1][1], dp[i-1][2])
dp[i][1] = costs[i][1] + min(dp[i-1][0], dp[i-1][2])
dp[i][2] = costs[i][2] + min(dp[i-1][0], dp[i-1][1])
func minCost(costs [][]int) int {
n := len(costs)
dp := make([][3]int, n)
dp[0] = [3]int{costs[0][0], costs[0][1], costs[0][2]}
for i := 1; i < n; i++ {
dp[i][0] = costs[i][0] + min(dp[i-1][1], dp[i-1][2])
dp[i][1] = costs[i][1] + min(dp[i-1][0], dp[i-1][2])
dp[i][2] = costs[i][2] + min(dp[i-1][0], dp[i-1][1])
}
return min(dp[n-1][0], dp[n-1][1], dp[n-1][2])
}
func min(a, b int) int {
if a < b {
return a
}
return b
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 1074. Number of Submatrices That Sum to Target
Сложность: hard
Дана матрица и целевое значение. Верните количество непустых подматриц, сумма элементов которых равна целевому значению.
Подматрица x1, y1, x2, y2 — это набор всех ячеек matrix[x][y] с x1 <= x <= x2 и y1 <= y <= y2.
Две подматрицы (x1, y1, x2, y2) и (x1', y1', x2', y2') различны, если у них есть какая-то различающаяся координата: например, если x1 != x1'.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте результат: count = 0. Вычислите количество строк: r = len(matrix) и количество столбцов: c = len(matrix[0]). Вычислите двумерную префиксную сумму ps, выделив еще одну строку и еще один столбец для нулевых значений.
2⃣ Итерируйте по строкам: r1 от 1 до r и r2 от r1 до r. Внутри этого двойного цикла фиксируйте левые и правые границы строк и инициализируйте хэш-таблицу для хранения префиксных сумм. Итерируйте по столбцам от 1 до c + 1, вычислите текущую префиксную сумму 1D curr_sum и увеличьте count на количество матриц, сумма которых равна target.
3⃣ Добавьте текущую префиксную сумму 1D в хэш-таблицу. Когда все итерации завершены, верните count.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана матрица и целевое значение. Верните количество непустых подматриц, сумма элементов которых равна целевому значению.
Подматрица x1, y1, x2, y2 — это набор всех ячеек matrix[x][y] с x1 <= x <= x2 и y1 <= y <= y2.
Две подматрицы (x1, y1, x2, y2) и (x1', y1', x2', y2') различны, если у них есть какая-то различающаяся координата: например, если x1 != x1'.
Пример:
Input: matrix = [[0,1,0],[1,1,1],[0,1,0]], target = 0
Output: 4
Explanation: The four 1x1 submatrices that only contain 0.
func numSubmatrixSumTarget(matrix [][]int, target int) int {
r, c := len(matrix), len(matrix[0])
ps := make([][]int, r+1)
for i := range ps {
ps[i] = make([]int, c+1)
}
for i := 1; i <= r; i++ {
for j := 1; j <= c; j++ {
ps[i][j] = ps[i-1][j] + ps[i][j-1] - ps[i-1][j-1] + matrix[i-1][j]
}
}
count := 0
for r1 := 1; r1 <= r; r2++ {
for r2 := r1; r2 <= r; r2++ {
h := map[int]int{0: 1}
for col := 1; col <= c; col++ {
currSum := ps[r2][col] - ps[r1-1][col]
if count, ok := h[currSum-target]; ok {
count += count
}
h[currSum]++
}
}
}
return count
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1213. Intersection of Three Sorted Arrays
Сложность: easy
Даны три целочисленных массива arr1, arr2 и arr3, отсортированных в строго возрастающем порядке. Верните отсортированный массив, содержащий только те целые числа, которые присутствуют во всех трех массивах.
Пример:
👨💻 Алгоритм:
1⃣ Инициализируйте counter как TreeMap для записи чисел, которые появляются в трех массивах, и количество их появлений.
2⃣ Пройдитесь по массивам arr1, arr2 и arr3, чтобы посчитать частоты появления элементов.
3⃣ Итерация через counter, чтобы найти числа, которые появляются три раза, и вернуть их в виде отсортированного массива.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Даны три целочисленных массива arr1, arr2 и arr3, отсортированных в строго возрастающем порядке. Верните отсортированный массив, содержащий только те целые числа, которые присутствуют во всех трех массивах.
Пример:
Input: arr1 = [1,2,3,4,5], arr2 = [1,2,5,7,9], arr3 = [1,3,4,5,8]
Output: [1,5]
Explanation: Only 1 and 5 appeared in the three arrays.
func arraysIntersection(arr1 []int, arr2 []int, arr3 []int) []int {
counter := make(map[int]int)
for _, e := range arr1 {
counter[e]++
}
for _, e := range arr2 {
counter[e]++
}
for _, e := range arr3 {
counter[e]++
}
var ans []int
for k, v := range counter {
if v == 3 {
ans = append(ans, k)
}
}
sort.Ints(ans)
return ans
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 188. Best Time to Buy and Sell Stock IV
Сложность: hard
Дан массив целых чисел prices, где prices[i] - это цена данной акции в i-й день, и целое число k.
Найдите максимальную прибыль, которую вы можете получить. Вы можете завершить не более чем k транзакций, т.е. вы можете купить не более k раз и продать не более k раз.
Обратите внимание: Вы не можете участвовать в нескольких транзакциях одновременно (т.е., вы должны продать акцию, прежде чем снова купить).
Пример:
👨💻 Алгоритм:
1⃣ Инициализация DP массива: Инициализируйте трехмерный массив dp, где dp[i][j][l] представляет максимальную прибыль на конец i-го дня с j оставшимися транзакциями и l акциями в портфеле. Начните с dp[0][0][0] = 0 (нет прибыли без акций и транзакций) и dp[0][1][1] = -prices[0] (покупка первой акции).
2⃣ Вычисление переходов: Для каждого дня и каждого возможного количества транзакций вычислите возможные действия: держать акцию, не держать акцию, купить акцию, если j > 0, или продать акцию. Обновляйте dp с использованием:
dp[i][j][1] = max(dp[i−1][j][1], dp[i−1][j−1][0] - prices[i]) (максимум между удержанием акции и покупкой новой).
dp[i][j][0] = max(dp[i−1][j][0], dp[i−1][j][1] + prices[i]) (максимум между неудержанием акции и продажей).
3⃣ Расчет результатов: По завершении всех дней, возвращайте максимальное значение dp[n-1][j][0] для всех j от 0 до k, что представляет максимальную прибыль без удержания акций на последний день. Обработайте специальный случай, когда 𝑘×2≥𝑛, чтобы избежать лишних расчетов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дан массив целых чисел prices, где prices[i] - это цена данной акции в i-й день, и целое число k.
Найдите максимальную прибыль, которую вы можете получить. Вы можете завершить не более чем k транзакций, т.е. вы можете купить не более k раз и продать не более k раз.
Обратите внимание: Вы не можете участвовать в нескольких транзакциях одновременно (т.е., вы должны продать акцию, прежде чем снова купить).
Пример:
Input: k = 2, prices = [2,4,1]
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
dp[i][j][1] = max(dp[i−1][j][1], dp[i−1][j−1][0] - prices[i]) (максимум между удержанием акции и покупкой новой).
dp[i][j][0] = max(dp[i−1][j][0], dp[i−1][j][1] + prices[i]) (максимум между неудержанием акции и продажей).
type Solution struct{}
func maxProfit(k int, prices []int) int {
n := len(prices)
if n == 0 || k == 0 {
return 0
}
if k*2 >= n {
res := 0
for i := 1; i < n; i++ {
if prices[i] > prices[i-1] {
res += prices[i] - prices[i-1]
}
}
return res
}
dp := make([][][]int, n)
for i := range dp {
dp[i] = make([][]int, k+1)
for j := range dp[i] {
dp[i][j] = make([]int, 2)
dp[i][j][0], dp[i][j][1] = -1<<31/2, -1<<31/2
}
}
dp[0][0][0] = 0
dp[0][1][1] = -prices[0]
for i := 1; i < n; i++ {
for j := 0; j <= k; j++ {
dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1]+prices[i])
if j > 0 {
dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0]-prices[i])
}
}
}
res := 0
for j := 0; j <= k; j++ {
res = max(res, dp[n-1][j][0])
}
return res
}
func max(x, y int) int {
if x > y {
return x
}
return y
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 109. Convert Sorted List to Binary Search Tree
Сложность: medium
Дана голова односвязного списка, элементы которого отсортированы в порядке возрастания. Преобразуйте его в сбалансированное по высоте бинарное дерево поиска.
Пример:
👨💻 Алгоритм:
1⃣ Поскольку нам дан односвязный список, а не массив, у нас нет прямого доступа к элементам списка по индексам. Нам нужно определить средний элемент односвязного списка. Мы можем использовать подход с двумя указателями для нахождения среднего элемента списка. В основном, у нас есть два указателя: slow_ptr и fast_ptr. slow_ptr перемещается на один узел за раз, тогда как fast_ptr перемещается на два узла за раз. К тому времени, как fast_ptr достигнет конца списка, slow_ptr окажется в середине списка. Для списка с четным количеством элементов любой из двух средних элементов может стать корнем BST.
2⃣ Как только мы находим средний элемент списка, мы отсоединяем часть списка слева от среднего элемента. Мы делаем это, сохраняя prev_ptr, который указывает на узел перед slow_ptr, т.е. prev_ptr.next = slow_ptr. Для отсоединения левой части мы просто делаем prev_ptr.next = None.
3⃣ Для создания сбалансированного по высоте BST нам нужно передать только голову связанного списка в функцию, которая преобразует его в BST. Таким образом, мы рекурсивно работаем с левой половиной списка, передавая оригинальную голову списка, и с правой половиной, передавая slow_ptr.next в качестве головы.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дана голова односвязного списка, элементы которого отсортированы в порядке возрастания. Преобразуйте его в сбалансированное по высоте бинарное дерево поиска.
Пример:
Input: head = [-10,-3,0,5,9]
Output: [0,-3,9,-10,null,5]
Explanation: One possible answer is [0,-3,9,-10,null,5], which represents the shown height balanced BST.
type ListNode struct {
Val int
Next *ListNode
}
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
func sortedListToBST(head *ListNode) *TreeNode {
if head == nil {
return nil
}
mid := findMiddleElement(head)
node := &TreeNode{
Val: mid.Val,
}
if head == mid {
return node
}
node.Left = sortedListToBST(head)
node.Right = sortedListToBST(mid.Next)
return node
}
func findMiddleElement(head *ListNode) *ListNode {
var prevPtr *ListNode = nil
slowPtr := head
fastPtr := head
for fastPtr != nil && fastPtr.Next != nil {
prevPtr = slowPtr
slowPtr = slowPtr.Next
fastPtr = fastPtr.Next.Next
}
if prevPtr != nil {
prevPtr.Next = nil
}
return slowPtr
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1125. Smallest Sufficient Team
Сложность: hard
В проекте у вас есть список необходимых навыков req_skills и список людей. i-й человек people[i] содержит список навыков, которыми обладает этот человек.
Рассмотрим достаточную команду: набор людей, такой что для каждого необходимого навыка из req_skills, есть по крайней мере один человек в команде, который обладает этим навыком. Мы можем представить эти команды индексами каждого человека.
Например, команда = [0, 1, 3] представляет людей с навыками people[0], people[1] и people[3].
Верните любую достаточную команду наименьшего возможного размера, представленную индексами каждого человека. Вы можете вернуть ответ в любом порядке.
Гарантируется, что ответ существует.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация и создание масок навыков:
Определите количество людей n и количество необходимых навыков m.
Создайте хэш-таблицу skillId, чтобы сопоставить каждому навыку уникальный индекс.
Создайте массив skillsMaskOfPerson, который будет содержать битовые маски навыков для каждого человека.
2⃣ Динамическое программирование (DP):
Создайте массив dp размера 2^m и заполните его значениями (1 << n) - 1.
Установите dp[0] в 0 (базовый случай).
Для каждого skillsMask от 1 до 2^m - 1:
- для каждого человека i:
- вычислите smallerSkillsMask как skillsMask & ~skillsMaskOfPerson[i].
- если smallerSkillsMask отличается от skillsMask, обновите dp[skillsMask], если новая команда лучше (имеет меньше установленных битов).
3⃣ Формирование ответа:
Извлеките ответ из dp и верните массив индексов людей, составляющих минимальную достаточную команду.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
В проекте у вас есть список необходимых навыков req_skills и список людей. i-й человек people[i] содержит список навыков, которыми обладает этот человек.
Рассмотрим достаточную команду: набор людей, такой что для каждого необходимого навыка из req_skills, есть по крайней мере один человек в команде, который обладает этим навыком. Мы можем представить эти команды индексами каждого человека.
Например, команда = [0, 1, 3] представляет людей с навыками people[0], people[1] и people[3].
Верните любую достаточную команду наименьшего возможного размера, представленную индексами каждого человека. Вы можете вернуть ответ в любом порядке.
Гарантируется, что ответ существует.
Пример:
Input: req_skills = ["algorithms","math","java","reactjs","csharp","aws"],
people = [["algorithms","math","java"],["algorithms","math","reactjs"],
["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]]
Output: [1,2]
Определите количество людей n и количество необходимых навыков m.
Создайте хэш-таблицу skillId, чтобы сопоставить каждому навыку уникальный индекс.
Создайте массив skillsMaskOfPerson, который будет содержать битовые маски навыков для каждого человека.
Создайте массив dp размера 2^m и заполните его значениями (1 << n) - 1.
Установите dp[0] в 0 (базовый случай).
Для каждого skillsMask от 1 до 2^m - 1:
- для каждого человека i:
- вычислите smallerSkillsMask как skillsMask & ~skillsMaskOfPerson[i].
- если smallerSkillsMask отличается от skillsMask, обновите dp[skillsMask], если новая команда лучше (имеет меньше установленных битов).
Извлеките ответ из dp и верните массив индексов людей, составляющих минимальную достаточную команду.
import "math/bits"
func smallestSufficientTeam(req_skills []string, people [][]string) []int {
n, m := len(people), len(req_skills)
skillId := make(map[string]int)
for i, skill := range req_skills {
skillId[skill] = i
}
skillsMaskOfPerson := make([]int, n)
for i, person := range people {
for _, skill := range person {
if id, ok := skillId[skill]; ok {
skillsMaskOfPerson[i] |= 1 << id
}
}
}
dp := make([]int64, 1<<m)
for i := range dp {
dp[i] = (1 << n) - 1
}
dp[0] = 0
for skillsMask := 1; skillsMask < (1 << m); skillsMask++ {
for i := 0; i < n; i++ {
smallerSkillsMask := skillsMask &^ skillsMaskOfPerson[i]
if smallerSkillsMask != skillsMask {
peopleMask := dp[smallerSkillsMask] | (1 << i)
if bits.OnesCount64(uint64(peopleMask)) < bits.OnesCount64(uint64(dp[skillsMask])) {
dp[skillsMask] = peopleMask
}
}
}
}
answerMask := dp[(1<<m)-1]
result := []int{}
for i := 0; i < n; i++ {
if (answerMask>>i)&1 == 1 {
result = append(result, i)
}
}
return result
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1007. Minimum Domino Rotations For Equal Row
Сложность: medium
В ряду домино, tops[i] и bottoms[i] представляют собой верхнюю и нижнюю половинки i-го домино. (Домино - это плитка с двумя числами от 1 до 6 - по одному на каждой половине плитки.) Мы можем повернуть i-е домино так, чтобы tops[i] и bottoms[i] поменялись значениями. Верните минимальное количество поворотов, чтобы все значения tops были одинаковыми или все значения bottoms были одинаковыми. Если это невозможно сделать, верните -1.
Пример:
👨💻 Алгоритм:
1⃣ Проверка кандидатов:
Для начала рассмотрим два кандидата для достижения цели: tops[0] и bottoms[0]. Это кандидаты для унификации значений в ряду домино, поскольку если есть решение, один из этих двух кандидатов должен быть в верхней или нижней строке всех домино.
2⃣ Подсчет поворотов для каждого кандидата:
Для каждого из кандидатов (tops[0] и bottoms[0]) подсчитайте количество поворотов, необходимых для унификации значений во всех tops или во всех bottoms.
Если какой-либо домино не может быть повернут для достижения требуемого кандидата, этот кандидат исключается из рассмотрения.
3⃣ Возврат минимального количества поворотов:
Верните минимальное количество поворотов из всех возможных кандидатов. Если ни один кандидат не подходит, верните -1.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
В ряду домино, tops[i] и bottoms[i] представляют собой верхнюю и нижнюю половинки i-го домино. (Домино - это плитка с двумя числами от 1 до 6 - по одному на каждой половине плитки.) Мы можем повернуть i-е домино так, чтобы tops[i] и bottoms[i] поменялись значениями. Верните минимальное количество поворотов, чтобы все значения tops были одинаковыми или все значения bottoms были одинаковыми. Если это невозможно сделать, верните -1.
Пример:
Input: tops = [2,1,2,4,2,2], bottoms = [5,2,6,2,3,2]
Output: 2
Для начала рассмотрим два кандидата для достижения цели: tops[0] и bottoms[0]. Это кандидаты для унификации значений в ряду домино, поскольку если есть решение, один из этих двух кандидатов должен быть в верхней или нижней строке всех домино.
Для каждого из кандидатов (tops[0] и bottoms[0]) подсчитайте количество поворотов, необходимых для унификации значений во всех tops или во всех bottoms.
Если какой-либо домино не может быть повернут для достижения требуемого кандидата, этот кандидат исключается из рассмотрения.
Верните минимальное количество поворотов из всех возможных кандидатов. Если ни один кандидат не подходит, верните -1.
func minDominoRotations(tops []int, bottoms []int) int {
check := func(x int) int {
rotationsA, rotationsB := 0, 0
for i := 0; i < len(tops); i++ {
if tops[i] != x && bottoms[i] != x {
return -1
} else if tops[i] != x {
rotationsA++
} else if bottoms[i] != x {
rotationsB++
}
}
return min(rotationsA, rotationsB)
}
rotations := check(tops[0])
if rotations != -1 || tops[0] == bottoms[0] {
return rotations
} else {
return check(bottoms[0])
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 284. Peeking Iterator
Сложность: medium
Создайте итератор, который поддерживает операцию peek (просмотр следующего элемента) на существующем итераторе, помимо операций hasNext (проверка наличия следующего элемента) и next (получение следующего элемента).
Реализуйте класс PeekingIterator:
PeekingIterator(Iterator<int> nums): Инициализирует объект с заданным итератором целых чисел.
int next(): Возвращает следующий элемент в массиве и перемещает указатель на следующий элемент.
boolean hasNext(): Возвращает true, если в массиве еще есть элементы.
int peek(): Возвращает следующий элемент в массиве без перемещения указателя.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация итератора:
В конструкторе класса PeekingIterator инициализируйте итератор и проверьте, есть ли следующий элемент. Если есть, установите его как next, иначе установите next в null.
2⃣ Операция peek:
Метод peek возвращает значение next, не перемещая указатель итератора.
3⃣ Операции next и hasNext:
Метод next возвращает текущее значение next, обновляет next к следующему элементу в итераторе и перемещает указатель итератора. Если нет следующего элемента, бросает исключение NoSuchElementException.
Метод hasNext возвращает true, если next не равно null, и false в противном случае.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Создайте итератор, который поддерживает операцию peek (просмотр следующего элемента) на существующем итераторе, помимо операций hasNext (проверка наличия следующего элемента) и next (получение следующего элемента).
Реализуйте класс PeekingIterator:
PeekingIterator(Iterator<int> nums): Инициализирует объект с заданным итератором целых чисел.
int next(): Возвращает следующий элемент в массиве и перемещает указатель на следующий элемент.
boolean hasNext(): Возвращает true, если в массиве еще есть элементы.
int peek(): Возвращает следующий элемент в массиве без перемещения указателя.
Пример:
Input
["PeekingIterator", "next", "peek", "next", "next", "hasNext"]
[[[1, 2, 3]], [], [], [], [], []]
Output
[null, 1, 2, 2, 3, false]
Explanation
PeekingIterator peekingIterator = new PeekingIterator([1, 2, 3]); // [1,2,3]
peekingIterator.next(); // return 1, the pointer moves to the next element [1,2,3].
peekingIterator.peek(); // return 2, the pointer does not move [1,2,3].
peekingIterator.next(); // return 2, the pointer moves to the next element [1,2,3]
peekingIterator.next(); // return 3, the pointer moves to the next element [1,2,3]
peekingIterator.hasNext(); // return False
В конструкторе класса PeekingIterator инициализируйте итератор и проверьте, есть ли следующий элемент. Если есть, установите его как next, иначе установите next в null.
Метод peek возвращает значение next, не перемещая указатель итератора.
Метод next возвращает текущее значение next, обновляет next к следующему элементу в итераторе и перемещает указатель итератора. Если нет следующего элемента, бросает исключение NoSuchElementException.
Метод hasNext возвращает true, если next не равно null, и false в противном случае.
type PeekingIterator struct {
iterator Iterator
nextElem *int
}
func Constructor(iter Iterator) *PeekingIterator {
var next *int
if iter.HasNext() {
val := iter.Next()
next = &val
}
return &PeekingIterator{iterator: iter, nextElem: next}
}
func (this *PeekingIterator) hasNext() bool {
return this.nextElem != nil
}
func (this *PeekingIterator) next() int {
current := *this.nextElem
if this.iterator.HasNext() {
val := this.iterator.Next()
this.nextElem = &val
} else {
this.nextElem = nil
}
return current
}
func (this *PeekingIterator) peek() int {
return *this.nextElem
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 224. Basic Calculator
Сложность: hard
Дана строка s, представляющая собой допустимое выражение, реализуйте базовый калькулятор для его вычисления и верните результат вычисления.
Примечание: нельзя использовать встроенные функции, которые оценивают строки как математические выражения, такие как eval().
Пример:
👨💻 Алгоритм:
1⃣ Итерация строки выражения в обратном порядке:
Читаем выражение символ за символом, формируя операнды из нескольких цифр, если символ - цифра.
Сохраняем операнды в стек, как только встречаем нецифровой символ.
2⃣ Обработка выражения внутри скобок:
Когда встречаем открывающую скобку '(', оцениваем выражение, удаляя операнды и операторы из стека до соответствующей закрывающей скобки.
Результат выражения помещаем обратно в стек.
3⃣ Финальная оценка выражения:
Продолжаем процесс до получения финального результата.
Если стек не пуст после обработки всех символов, оцениваем оставшиеся элементы как одно финальное выражение.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: hard
Дана строка s, представляющая собой допустимое выражение, реализуйте базовый калькулятор для его вычисления и верните результат вычисления.
Примечание: нельзя использовать встроенные функции, которые оценивают строки как математические выражения, такие как eval().
Пример:
Input: s = "(1+(4+5+2)-3)+(6+8)"
Output: 23
Читаем выражение символ за символом, формируя операнды из нескольких цифр, если символ - цифра.
Сохраняем операнды в стек, как только встречаем нецифровой символ.
Когда встречаем открывающую скобку '(', оцениваем выражение, удаляя операнды и операторы из стека до соответствующей закрывающей скобки.
Результат выражения помещаем обратно в стек.
Продолжаем процесс до получения финального результата.
Если стек не пуст после обработки всех символов, оцениваем оставшиеся элементы как одно финальное выражение.
package main
import (
"fmt"
"math"
"strconv"
"unicode"
)
type Solution struct{}
func (s Solution) evaluateExpr(stack *[]interface{}) int {
if len(*stack) == 0 || !isInt((*stack)[len(*stack)-1]) {
*stack = append(*stack, 0)
}
res := pop(stack).(int)
for len(*stack) != 0 && (*stack)[len(*stack)-1].(rune) != ')' {
sign := pop(stack).(rune)
if sign == '+' {
res += pop(stack).(int)
} else {
res -= pop(stack).(int)
}
}
return res
}
func (s Solution) calculate(expr string) int {
operand := 0
n := 0
stack := []interface{}{}
for i := len(expr) - 1; i >= 0; i-- {
ch := expr[i]
if unicode.IsDigit(rune(ch)) {
operand = int(math.Pow(10, float64(n))) * (int(ch-'0')) + operand
n += 1
} else if ch != ' ' {
if n != 0 {
stack = append(stack, operand)
n = 0
operand = 0
}
if ch == '(' {
res := s.evaluateExpr(&stack)
pop(&stack)
stack = append(stack, res)
} else {
stack = append(stack, rune(ch))
}
}
}
if n != 0 {
stack = append(stack, operand)
}
return s.evaluateExpr(&stack)
}
func pop(stack *[]interface{}) interface{} {
if len(*stack) == 0 {
return nil
}
res := (*stack)[len(*stack)-1]
*stack = (*stack)[:len(*stack)-1]
return res
}
func isInt(value interface{}) bool {
_, ok := value.(int)
return ok
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 217. Contains Duplicate
Сложность: easy
Дан массив целых чисел nums. Верните true, если любое значение появляется в массиве хотя бы дважды, и верните false, если каждый элемент уникален.
Пример:
👨💻 Алгоритм:
1⃣ Отсортируйте массив nums по возрастанию.
2⃣ Итерируйте по отсортированному массиву и сравнивайте каждое число с следующим.
3⃣ Если любое число совпадает с следующим, верните true. Если цикл завершится без совпадений, верните false.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: easy
Дан массив целых чисел nums. Верните true, если любое значение появляется в массиве хотя бы дважды, и верните false, если каждый элемент уникален.
Пример:
Input: nums = [1,2,3,4]
Output: false
import "sort"
func containsDuplicate(nums []int) bool {
sort.Ints(nums)
for i := 0; i < len(nums)-1; i++ {
if nums[i] == nums[i+1] {
return true
}
}
return false
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 565. Array Nesting
Сложность: medium
Дан массив целых чисел nums длиной n, где nums является перестановкой чисел в диапазоне [0, n - 1].
Вы должны построить множество s[k] = {nums[k], nums[nums[k]], nums[nums[nums[k]]], ...} при соблюдении следующего правила:
Первый элемент в s[k] начинается с выбора элемента nums[k] с индексом k.
Следующий элемент в s[k] должен быть nums[nums[k]], затем nums[nums[nums[k]]], и так далее.
Мы прекращаем добавлять элементы непосредственно перед тем, как в s[k] появится дубликат.
Верните длину самого длинного множества s[k].
Пример:
👨💻 Алгоритм:
1⃣ Создайте массив для отслеживания посещенных элементов.
2⃣ Для каждого элемента в nums, если он не посещен, начните формирование множества s[k], последовательно переходя по элементам, пока не встретится уже посещенный элемент.
3⃣ Обновите максимальную длину найденного множества.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Дан массив целых чисел nums длиной n, где nums является перестановкой чисел в диапазоне [0, n - 1].
Вы должны построить множество s[k] = {nums[k], nums[nums[k]], nums[nums[nums[k]]], ...} при соблюдении следующего правила:
Первый элемент в s[k] начинается с выбора элемента nums[k] с индексом k.
Следующий элемент в s[k] должен быть nums[nums[k]], затем nums[nums[nums[k]]], и так далее.
Мы прекращаем добавлять элементы непосредственно перед тем, как в s[k] появится дубликат.
Верните длину самого длинного множества s[k].
Пример:
Input: nums = [5,4,0,3,1,6,2]
Output: 4
Explanation:
nums[0] = 5, nums[1] = 4, nums[2] = 0, nums[3] = 3, nums[4] = 1, nums[5] = 6, nums[6] = 2.
One of the longest sets s[k]:
s[0] = {nums[0], nums[5], nums[6], nums[2]} = {5, 6, 2, 0}
func arrayNesting(nums []int) int {
visited := make([]bool, len(nums))
maxLength := 0
for i := 0; i < len(nums); i++ {
if !visited[i] {
start := i
count := 0
for !visited[start] {
visited[start] = true
start = nums[start]
count++
}
if count > maxLength {
maxLength = count
}
}
}
return maxLength
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 417. Pacific Atlantic Water Flow
Сложность: medium
Имеется прямоугольный остров размером m x n, который граничит с Тихим и Атлантическим океанами. Тихий океан касается левого и верхнего краев острова, а Атлантический океан - правого и нижнего краев. Остров разбит на сетку квадратных ячеек. Вам дана целочисленная матрица heights размером m x n, где heights[r][c] - высота над уровнем моря клетки с координатами (r, c). На острове выпадает много осадков, и дождевая вода может стекать в соседние клетки прямо на север, юг, восток и запад, если высота соседней клетки меньше или равна высоте текущей клетки. Вода может течь из любой клетки, прилегающей к океану, в океан. Верните двумерный список координат сетки result, где result[i] = [ri, ci] означает, что дождевая вода может течь из клетки (ri, ci) как в Тихий, так и в Атлантический океаны.
Пример:
👨💻 Алгоритм:
1⃣ Определите две матрицы для отслеживания клеток, из которых вода может течь в Тихий и Атлантический океаны, используя поиск в глубину (DFS) или поиск в ширину (BFS), начиная с границ, примыкающих к каждому океану.
2⃣ Выполните поиск для каждого океана, обновляя матрицы достижимости.
3⃣ Соберите координаты клеток, которые могут стекать в оба океана, проверяя пересечение двух матриц достижимости.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Имеется прямоугольный остров размером m x n, который граничит с Тихим и Атлантическим океанами. Тихий океан касается левого и верхнего краев острова, а Атлантический океан - правого и нижнего краев. Остров разбит на сетку квадратных ячеек. Вам дана целочисленная матрица heights размером m x n, где heights[r][c] - высота над уровнем моря клетки с координатами (r, c). На острове выпадает много осадков, и дождевая вода может стекать в соседние клетки прямо на север, юг, восток и запад, если высота соседней клетки меньше или равна высоте текущей клетки. Вода может течь из любой клетки, прилегающей к океану, в океан. Верните двумерный список координат сетки result, где result[i] = [ri, ci] означает, что дождевая вода может течь из клетки (ri, ci) как в Тихий, так и в Атлантический океаны.
Пример:
Input: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]
Output: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]
package main
func pacificAtlantic(heights [][]int) [][]int {
m, n := len(heights), len(heights[0])
pacific := make([][]bool, m)
atlantic := make([][]bool, m)
for i := range pacific {
pacific[i] = make([]bool, n)
atlantic[i] = make([]bool, n)
}
directions := [][]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}
var dfs func(r, c int, ocean [][]bool)
dfs = func(r, c int, ocean [][]bool) {
ocean[r][c] = true
for _, dir := range directions {
nr, nc := r+dir[0], c+dir[1]
if nr >= 0 && nc >= 0 && nr < m && nc < n && !ocean[nr][nc] && heights[nr][nc] >= heights[r][c] {
dfs(nr, nc, ocean)
}
}
}
for i := 0; i < m; i++ {
dfs(i, 0, pacific)
dfs(i, n-1, atlantic)
}
for j := 0; j < n; j++ {
dfs(0, j, pacific)
dfs(m-1, j, atlantic)
}
result := [][]int{}
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if pacific[i][j] && atlantic[i][j] {
result = append(result, []int{i, j})
}
}
}
return result
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 341. Flatten Nested List Iterator
Сложность: medium
Вам дан вложенный список целых чисел nestedList. Каждый элемент либо является целым числом, либо списком, элементы которого также могут быть целыми числами или другими списками. Реализуйте итератор для его развёртки.
Реализуйте класс NestedIterator:
NestedIterator(List<NestedInteger> nestedList) Инициализирует итератор вложенным списком nestedList.
int next() Возвращает следующий целый элемент вложенного списка.
boolean hasNext() Возвращает true, если в вложенном списке еще остались целые числа, и false в противном случае.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация
Сохраняйте исходный вложенный список в стеке или очереди. Используйте стек для сохранения состояния итерации по вложенным спискам.
2⃣ Метод next()
Возвращает следующий целый элемент из стека или очереди. Если текущий элемент является списком, развёртывайте его и добавляйте элементы в стек.
3⃣ Метод hasNext()
Проверяет, есть ли в стеке или очереди оставшиеся целые элементы. Если на вершине стека находится список, развёртывайте его до тех пор, пока не встретится целый элемент.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан вложенный список целых чисел nestedList. Каждый элемент либо является целым числом, либо списком, элементы которого также могут быть целыми числами или другими списками. Реализуйте итератор для его развёртки.
Реализуйте класс NestedIterator:
NestedIterator(List<NestedInteger> nestedList) Инициализирует итератор вложенным списком nestedList.
int next() Возвращает следующий целый элемент вложенного списка.
boolean hasNext() Возвращает true, если в вложенном списке еще остались целые числа, и false в противном случае.
Пример:
Input: nestedList = [[1,1],2,[1,1]]
Output: [1,1,2,1,1]
Explanation: By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1].
Сохраняйте исходный вложенный список в стеке или очереди. Используйте стек для сохранения состояния итерации по вложенным спискам.
Возвращает следующий целый элемент из стека или очереди. Если текущий элемент является списком, развёртывайте его и добавляйте элементы в стек.
Проверяет, есть ли в стеке или очереди оставшиеся целые элементы. Если на вершине стека находится список, развёртывайте его до тех пор, пока не встретится целый элемент.
type NestedIterator struct {
stack []*NestedInteger
}
func Constructor(nestedList []*NestedInteger) *NestedIterator {
it := &NestedIterator{}
it.flatten(nestedList)
return it
}
func (this *NestedIterator) flatten(nestedList []*NestedInteger) {
for i := len(nestedList) - 1; i >= 0; i-- {
this.stack = append(this.stack, nestedList[i])
}
}
func (this *NestedIterator) Next() int {
return this.stack[len(this.stack)-1].GetInteger()
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Задача: 621. Task Scheduler
Сложность: medium
Вам дан массив задач процессора, каждая из которых представлена буквами от A до Z, и время охлаждения, n. Каждый цикл или интервал позволяет завершить одну задачу. Задачи могут быть выполнены в любом порядке, но есть ограничение: одинаковые задачи должны быть разделены не менее чем n интервалами из-за времени охлаждения. Верните минимальное количество интервалов, необходимое для выполнения всех задач.
Пример:
👨💻 Алгоритм:
1⃣ Подсчитайте количество каждой задачи и найдите максимальное количество вхождений (maxFreq).
2⃣ Вычислите количество интервалов, необходимых для задач с maxFreq: (maxFreq - 1) * (n + 1) + countMaxFreq, где countMaxFreq - количество задач, имеющих maxFreq.
3⃣ Верните максимум между вычисленным значением и длиной массива задач, поскольку некоторые задачи могут заполнять интервал до n.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дан массив задач процессора, каждая из которых представлена буквами от A до Z, и время охлаждения, n. Каждый цикл или интервал позволяет завершить одну задачу. Задачи могут быть выполнены в любом порядке, но есть ограничение: одинаковые задачи должны быть разделены не менее чем n интервалами из-за времени охлаждения. Верните минимальное количество интервалов, необходимое для выполнения всех задач.
Пример:
Input: tasks = ["A","A","A","B","B","B"], n = 2
Output: 8
package main
import (
"fmt"
"math"
)
func leastInterval(tasks []byte, n int) int {
taskCounts := make(map[byte]int)
for _, task := range tasks {
taskCounts[task]++
}
maxFreq := 0
for _, count := range taskCounts {
if count > maxFreq {
maxFreq = count
}
}
countMaxFreq := 0
for _, count := range taskCounts {
if count == maxFreq {
countMaxFreq++
}
}
return int(math.Max(float64(len(tasks)), float64((maxFreq-1)*(n+1)+countMaxFreq)))
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 371. Sum of Two Integers
Сложность: medium
Даны два целых числа a и b. Вернуть сумму этих двух чисел, не используя операторы + и -.
Пример:
👨💻 Алгоритм:
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.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Даны два целых числа a и b. Вернуть сумму этих двух чисел, не используя операторы + и -.
Пример:
Input: a = 1, b = 2
Output: 3
Пока перенос не равен нулю (y != 0):
Текущий ответ без переноса равен XOR x и y: answer = x ^ y.
Текущий перенос равен сдвинутому влево AND x и y: carry = (x & y) << 1.
Подготовьтесь к следующему циклу: x = answer, y = carry.
Верните x * sign.
Пока заимствование не равно нулю (y != 0):
Текущий ответ без заимствования равен XOR x и y: answer = x ^ y.
Текущее заимствование равно сдвинутому влево AND НЕ x и y: borrow = ((~x) & y) << 1.
Подготовьтесь к следующему циклу: x = answer, y = borrow.
Верните x * sign.
package main
import "math"
func getSum(a int, b int) int {
x, y := int(math.Abs(float64(a))), int(math.Abs(float64(b)))
if x < y {
return getSum(b, a)
}
sign := 1
if a < 0 {
sign = -1
}
if a * b >= 0 {
for y != 0 {
carry := (x & y) << 1
x ^= y
y = carry
}
} else {
for y != 0 {
borrow := ((^x) & y) << 1
x ^= y
y = borrow
}
}
return x * sign
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
Задача: 848. Shifting Letters
Сложность: medium
Вам дана строка s из строчных букв английского алфавита и целочисленный массив shifts такой же длины.
Назовем shift() буквы следующей буквой в алфавите (с переходом так, что 'z' становится 'a').
Например, shift('a') = 'b', shift('t') = 'u', и shift('z') = 'a'.
Теперь для каждого shifts[i] = x мы хотим сдвинуть первые i + 1 букв строки s на x раз.
Верните итоговую строку после применения всех таких сдвигов к s.
Пример:
👨💻 Алгоритм:
1⃣ Вычислите общее количество сдвигов для всех символов строки, используя массив shifts.
2⃣ Пройдите по строке s и примените вычисленные сдвиги к каждому символу, начиная с первого и уменьшая количество сдвигов на текущем шаге.
3⃣ Постройте и верните итоговую строку после всех сдвигов.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана строка s из строчных букв английского алфавита и целочисленный массив shifts такой же длины.
Назовем shift() буквы следующей буквой в алфавите (с переходом так, что 'z' становится 'a').
Например, shift('a') = 'b', shift('t') = 'u', и shift('z') = 'a'.
Теперь для каждого shifts[i] = x мы хотим сдвинуть первые i + 1 букв строки s на x раз.
Верните итоговую строку после применения всех таких сдвигов к s.
Пример:
Input: s = "abc", shifts = [3,5,9]
Output: "rpl"
Explanation: We start with "abc".
After shifting the first 1 letters of s by 3, we have "dbc".
After shifting the first 2 letters of s by 5, we have "igc".
After shifting the first 3 letters of s by 9, we have "rpl", the answer.
func shiftingLetters(s string, shifts []int) string {
totalShifts := 0
for _, shift := range shifts {
totalShifts = (totalShifts + shift) % 26
}
result := make([]byte, len(s))
for i := 0; i < len(s); i++ {
newCharValue := (int(s[i]-'a') + totalShifts) % 26
result[i] = byte(newCharValue + 'a')
totalShifts = (totalShifts - shifts[i] + 26) % 26
}
return string(result)
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1236. Web Crawler
Сложность: medium
Учитывая url startUrl и интерфейс HtmlParser, реализуйте веб-краулер для просмотра всех ссылок, которые находятся под тем же именем хоста, что и startUrl.Верните все ссылки, полученные вашим краулером, в любом порядке. Ваш краулер должен: Начинать со страницы: startUrl Вызывать HtmlParser.getUrls(url), чтобы получить все ссылки с веб-страницы с заданным url. Не просматривайте одну и ту же ссылку дважды. Исследуйте только те ссылки, которые находятся под тем же именем хоста, что и startUrl. Как показано в примере url выше, имя хоста - example.org. Для простоты можно считать, что все урлы используют протокол http без указания порта. Например, урлы https://leetcode.com/problems и https://leetcode.com/contest находятся под одним и тем же именем хоста, а урлы https://example.org/test и https://example.com/abc не находятся под одним и тем же именем хоста.
Пример:
👨💻 Алгоритм:
1⃣ Извлечение имени хоста:
Сначала извлекаем имя хоста из начального URL для проверки всех последующих ссылок.
2⃣ Использование очереди для BFS:
Начинаем с начального URL и помещаем его в очередь.
Пока очередь не пуста, извлекаем текущий URL, получаем все ссылки с этой страницы, и для каждой ссылки проверяем, принадлежит ли она тому же имени хоста.
3⃣ Если да, и если мы еще не посещали эту ссылку, добавляем ее в очередь и отмечаем как посещенную.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Учитывая url startUrl и интерфейс HtmlParser, реализуйте веб-краулер для просмотра всех ссылок, которые находятся под тем же именем хоста, что и startUrl.Верните все ссылки, полученные вашим краулером, в любом порядке. Ваш краулер должен: Начинать со страницы: startUrl Вызывать HtmlParser.getUrls(url), чтобы получить все ссылки с веб-страницы с заданным url. Не просматривайте одну и ту же ссылку дважды. Исследуйте только те ссылки, которые находятся под тем же именем хоста, что и startUrl. Как показано в примере url выше, имя хоста - example.org. Для простоты можно считать, что все урлы используют протокол http без указания порта. Например, урлы https://leetcode.com/problems и https://leetcode.com/contest находятся под одним и тем же именем хоста, а урлы https://example.org/test и https://example.com/abc не находятся под одним и тем же именем хоста.
Пример:
Input:
urls = [
"https://news.yahoo.com",
"https://news.yahoo.com/news",
"https://news.yahoo.com/news/topics/",
"https://news.google.com",
"https://news.yahoo.com/us"
]
edges = [[2,0],[2,1],[3,2],[3,1],[0,4]]
startUrl = "https://news.yahoo.com/news/topics/"
Output: [
"https://news.yahoo.com",
"https://news.yahoo.com/news",
"https://news.yahoo.com/news/topics/",
"https://news.yahoo.com/us"
]
Сначала извлекаем имя хоста из начального URL для проверки всех последующих ссылок.
Начинаем с начального URL и помещаем его в очередь.
Пока очередь не пуста, извлекаем текущий URL, получаем все ссылки с этой страницы, и для каждой ссылки проверяем, принадлежит ли она тому же имени хоста.
package main
import (
"net/url"
"strings"
)
type HtmlParser interface {
GetUrls(url string) []string
}
func extractHostname(rawurl string) string {
parsedUrl, err := url.Parse(rawurl)
if err != nil {
return ""
}
return parsedUrl.Host
}
func crawl(startUrl string, htmlParser HtmlParser) []string {
hostname := extractHostname(startUrl)
visited := make(map[string]bool)
queue := []string{startUrl}
visited[startUrl] = true
for len(queue) > 0 {
url := queue[0]
queue = queue[1:]
for _, nextUrl := range htmlParser.GetUrls(url) {
if !visited[nextUrl] && extractHostname(nextUrl) == hostname {
visited[nextUrl] = true
queue = append(queue, nextUrl)
}
}
}
result := []string{}
for url := range visited {
result = append(result, url)
}
return result
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Задача: 1019. Next Greater Node In Linked List
Сложность: medium
Вам дана голова связного списка с n узлами. Для каждого узла в списке найдите значение следующего большего узла. То есть для каждого узла найдите значение первого узла, который находится рядом с ним и имеет строго большее значение, чем он. Верните целочисленный массив answer, где answer[i] - это значение следующего большего узла ith-узла (с индексацией по 1). Если у узла ith нет следующего большего узла, установите answer[i] = 0.
Пример:
👨💻 Алгоритм:
1⃣ Инициализация переменных:
Пройдитесь по всему списку и сохраните значения узлов в массив.
Инициализируйте стек для хранения индексов узлов, которые нужно обработать.
2⃣ Поиск следующего большего элемента:
Итерируйте по массиву значений узлов.
Для каждого элемента, пока стек не пуст и текущий элемент больше, чем элемент на вершине стека, обновите массив ответов значением текущего элемента и удалите элемент из стека.
Добавьте текущий индекс в стек.
3⃣ Заполнение оставшихся значений:
Для всех индексов, оставшихся в стеке, установите значение ответа равным 0, так как для них не найдено большего элемента.
😎 Решение:
Ставь 👍 и забирай 📚 Базу знаний
Сложность: medium
Вам дана голова связного списка с n узлами. Для каждого узла в списке найдите значение следующего большего узла. То есть для каждого узла найдите значение первого узла, который находится рядом с ним и имеет строго большее значение, чем он. Верните целочисленный массив answer, где answer[i] - это значение следующего большего узла ith-узла (с индексацией по 1). Если у узла ith нет следующего большего узла, установите answer[i] = 0.
Пример:
Input: head = [2,1,5]
Output: [5,5,0]
Пройдитесь по всему списку и сохраните значения узлов в массив.
Инициализируйте стек для хранения индексов узлов, которые нужно обработать.
Итерируйте по массиву значений узлов.
Для каждого элемента, пока стек не пуст и текущий элемент больше, чем элемент на вершине стека, обновите массив ответов значением текущего элемента и удалите элемент из стека.
Добавьте текущий индекс в стек.
Для всех индексов, оставшихся в стеке, установите значение ответа равным 0, так как для них не найдено большего элемента.
type ListNode struct {
Val int
Next *ListNode
}
func nextLargerNodes(head *ListNode) []int {
var values []int
for head != nil {
values = append(values, head.Val)
head = head.Next
}
answer := make([]int, len(values))
stack := []int{}
for i, value := range values {
for len(stack) > 0 && values[stack[len(stack)-1]] < value {
answer[stack[len(stack)-1]] = value
stack = stack[:len(stack)-1]
}
stack = append(stack, i)
}
return answer
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1