Golang вопросы собеседований
13.5K subscribers
625 photos
3 videos
1 file
432 links
@notxxx1 - админ

@Golang_google - Golang для разработчиков

@itchannels_telegram - 🔥лучшие из ит

@golangl - chat

@golangtests - golang tests

@golang_jobsgo - go chat jobs

@ai_machinelearning_big_data - AI

@data_analysis_ml

РКН: clck.ru/3FmtKd
加入频道
👣 На вход подаются два неупорядоченных слайса любой длины. Необходимо написать функцию, которая возвращает их пересечение.

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

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

package main

import (
"fmt"
)

// На вход подаются два неупорядоченных массива любой длины.
// Необходимо написать функцию, которая возвращает пересечение массивов
func intersection(a, b []int) []int {
counter := make(map[int]int)
var result []int

for _, elem := range a {
counter[elem]++
}

for _, elem := range b {
if count, ok := counter[elem]; ok && count > 0 {
counter[elem] -= 1
result = append(result, elem)
}
}
return result
}

func main() {

a := []int{23, 3, 1, 2}
b := []int{6, 2, 4, 23}
// [2, 23]
fmt.Printf("%v\n", intersection(a, b))
a = []int{1, 1, 1}
b = []int{1, 1, 1, 1}
// [1, 1, 1]
fmt.Printf("%v\n", intersection(a, b))
}


Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Почему Done() из интерфейса Context возвращает <-chan struct{}? Из какой горутины у нас что то записывается в этот канал и почему с этого канала возвращается пустая структура?

Метод Done() интерфейса Context возвращает канал <-chan struct{} для того, чтобы обеспечить механизм для оповещения о завершении операции в асинхронной среде. Когда операция завершается или контекст отменяется, канал закрывается. При этом значение пустой структуры struct{} записывается в этот канал, чтобы сигнализировать о завершении операции.

Обычно, главная горутина начинает операцию, создавая контекст, и передает его во все создаваемые горутины, которые выполняют асинхронную работу. Если в какой-то момент операция должна быть завершена, главная горутина вызывает метод cancel() у контекста. Это приводит к закрытию канала Done() во всех горутинах, подписанных на этот контекст. Когда горутина получает закрытый канал, это означает, что операция должна быть завершена.

Значение пустой структуры struct{} используется в качестве сигнала о завершении операции, потому что оно не занимает память и может быть передано по каналу без накладных расходов. Таким образом, когда канал закрывается, это означает, что операция завершена, и это сигнализирует всем горутинам, которые ждут завершения операции, что они могут продолжить выполнение.

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Экономное вычисление выражений в польской записи

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

Например, выражение в польской записи выглядит как

(* 5 (+ 3 4))

Пусть выражения в польской записи состоят из имён переменных (от a до z), круглых скобок и трёх знаков операций: #, $ и @ (смысл операций мы определять не будем).

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

Требуется составить программу econom.go, вычисляющую количество операций, которые нужно выполнить для экономного вычисления выражения. Примеры работы программы приведены в таблице:

Набор тестов для программы экономного вычисления выражений в польской записи

Выражение Количество операций
x 0
($xy) 1
($(@ab)c) 2
(#i($jk)) 2
(#($ab)($ab)) 2
(@(#ab)($ab)) 3
(#($a($b($cd)))(@($b($cd))($a($b($cd))))) 5
(#($(#xy)($(#ab)(#ab)))(@z($(#ab)(#ab)))) 6

Решение

package main

func main() {
println(opCount("(#($(#xy)($(#ab)(#ab)))(@z($(#ab)(#ab))))"))
println(opCount("($xy)"))
println(opCount("x"))
}

func opCount(expr string) int {
expressions := map[string]bool{}
var openBraces []int
for i, c := range expr {
switch c {
case '(':
openBraces = append(openBraces, i)
case ')':
lastOpenBrace := len(openBraces) - 1
subExprStart := openBraces[lastOpenBrace]
subExpr := expr[subExprStart:i]
expressions[subExpr] = true
openBraces = openBraces[:lastOpenBrace]
}
}
return len(expressions)
}

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

const oper = node_t("oper")
const expr = node_t("expr")

type node struct {
t node_t
v string
}

func opCount(input string) int {
expressions := map[string]bool{}
var stack []node
for _, c := range input {
switch c {
case '$', '#', '@':
stack = append(stack, node{t: oper, v: fmt.Sprintf("%s", c)})
default:
stack = append(stack, node{t: expr, v: fmt.Sprintf("%s", c)})
}
for canFold(stack) {
lastIdx := len(stack) - 1
operIdx := lastIdx - 2
folded := node{t: expr, v: stack[operIdx].v + stack[operIdx+1].v + stack[operIdx+2].v}
expressions[folded.v] = true
stack[operIdx] = folded
stack = stack[:operIdx+1]
}
}
return len(expressions)
}

func canFold(stack []node) bool {
stackLen := len(stack)
return stackLen >= 3 && stack[stackLen-3].t == oper && stack[stackLen-2].t == expr && stack[stackLen-1].t == expr
}


Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Golang
👣 Тестовое задание в Keenetic (NDMSystem) на junior+/Midle- программиста.

# Очередь на go с REST интерфейсом

## ТЗ

Реализовать брокер очередей в виде веб сервиса. Сервис должен обрабатывать 2 метода:

1. PUT /queue?v=message
Положить сообщение message в очередь с именем queue (имя очереди может
быть любое), пример:

curl -XPUT http://127.0.0.1/pet?v=cat
curl -XPUT http://127.0.0.1/pet?v=dog
curl -XPUT http://127.0.0.1/role?v=manager
curl -XPUT http://127.0.0.1/role?v=executive


в ответ {пустое тело + статус 200 (ok)}
в случае отсутствия параметра v - пустое тело + статус 400 (bad request)

2. GET /queue

Забрать (по принципу FIFO) из очереди с названием queue сообщение и вернуть в теле http запроса, пример (результат, который должен быть при выполненных put’ах выше):

curl http://127.0.0.1/pet => cat
curl http://127.0.0.1/pet => dog
curl http://127.0.0.1/pet => {пустое тело + статус 404 (not found)}
curl http://127.0.0.1/pet => {пустое тело + статус 404 (not found)}
curl http://127.0.0.1/role => manager
curl http://127.0.0.1/role => executive
curl http://127.0.0.1/role => {пустое тело + статус 404 (not found)}


при GET-запросах сделать возможность задавать аргумент timeout

curl http://127.0.0.1/pet?timeout=N

если в очереди нет готового сообщения получатель должен ждать либо до момента прихода сообщения либо до истечения таймаута (N - кол-во секунд). В случае, если сообщение так и не появилось - возвращать код 404. Получатели должны получать сообщения в том же порядке как от них поступал запрос, если 2 получателя ждут сообщения (используют таймаут), то первое сообщение должен получить тот, кто первый запросил.

Порт, на котором будет слушать сервис, должен задаваться в аргументах командной строки.

Запрещается пользоваться какими либо сторонними пакетами кроме стандартных библиотек. (задача в написании кода, а не в использовании чужого)

Желательно (но не обязательно) весь код расположить в одном go-файле (предполагается, что решение будет не больше 500 строк кода) для удобства проверки, никаких дополнительных файлов readme и т.п. не требуется, создание классической структуры каталогов (cmd/internal/...) не требуется.

Комментарии приветствуются и помогут нам понять ход Ваших мыслей при разработке.

Лаконичность кода будет восприниматься крайне положительно, не нужна "гибкость" больше, чем требуется для решения именно этой задачи, не нужны логи процесса работы программы (только обработка ошибок), никакого дебага и т.д... чем меньше кода - тем лучше!

Оцениваться корректность реализации (заданные условия выполняются),архитектурная составляющая (нет лишних действий в программе, только
решающие задачи программы), лаконичность и понятность кода (субъективно, конечно, но думайте о том, насколько будет понятен ваш. код для других, это куда более важно в командной разработке, чем сложный "крутой" код).

@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Тестовое задание дорожки в парке

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

Программа должна считывать со стандартного потока ввода количество аттракционов и их координаты. При этом координаты каждого аттракциона задаются парой целых чисел (в декартовой системе).

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

Например, для входных данных

12
2 4
2 5
3 4
3 5
6 5
6 6
7 5
7 6
5 1
5 2
6 1
6 2
программа должна выводить число 14.83.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Составьте программу, выполняющую построение графа делителей натурального числа такого, что .

Вершинами графа делителей являются все делители числа x, такого, что 0<x<2^32.

Ребро соединяет вершины u и v в том случае, если u делится на v, и не существует такого w, что u делится на v, и w делится на u.

Пример графа делителей изображён на рисунке.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Примеры, упражнения и тесты на Golang

Лучший способ изучить новый язык программирования — это практика. В этом репозитории собрано более 100 задач для Go. Изначально автор создал проект для своего курса, но позже добавил упражнения для всех желающих изучить этот язык:

🖥 Github

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Вопросы и ответы для собеседования Back-end/Golang разработчика и не только

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

🖥 Github

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Мои собеседования (Golang developer)

Привет, меня зовут Олег, я разработчик со стажем почти 10 лет.

Разработкой начал заниматься ещё со старшей школы, изучал C/C++ (очень пригодилось при написании скриптов в injection для ультимы онлайн). Профессионально начал работать разработчиком приблизительно с 2014, основной язык до 2020 года был C# с примесью C++. Сначала разрабатывал и поддерживал некоторые проекты в банковской сфере, потом резко поменял предметную область и ушёл писать софт для автоматизации работы одного строительного девелопера. На начальных этапах это было огромное легаси на C# от бывшего архитектора, решившего стать программистом, с кучей багов и неочевидных решений, пришлось много переписывать.

Со временем появились задачи, которые не были привязаны к языку и технологиям в принципе (изначально писал, по сути, плагины к CAD-приложениям), и я попробовал Golang, а вместе с ним и микросервисы, NoSQL, gRPC и прочие модные штуки. Побывал в шкуре админа-девопса, так как новые сервисы я запускал и поддерживал сам.

Некоторое время назад наткнулся на пост про собеседования и решил рассказать Хабру про свой опыт. Возможно, кому-то он окажется полезным.

Читать

@golang_interview
Арифметическое выражение (arith.go)

Составьте программу arith.go, вычисляющую значение скобочного арифметического выражения.

Арифметическое выражение считывается из аргументов командной строки и представляет собой строку, содержащую целые числа от 0 до 2 в 31 степени, знаки четырёх арифметических операций, имена переменных, круглые скобки и пробелы. Имена переменных представляют собой последовательности латинских букв и цифр, начинающиеся с буквы. Арифметические операции — целочисленные, то есть 5/2 даёт 2, а не 2.5. Пробелы не несут никакого смысла и должны игнорироваться программой.

Примеры выражений, которые могут быть поданы на вход программе:

-x * (x+10) * (128/x-5)
Length * Height * Depth


Грамматика для арифметических выражений записывается как

<E> ::= <E> + <T> | <E> - <T> | <T>.
<T> ::= <T> * <F> | <T> / <F> | <F>.
<F> ::= <number> | <var> | ( <E> ) | - <F>.


Здесь number и var обозначают множества терминальных символов, соответствующих числам и именам переменных.

После удаления левой рекурсии получается LL(1)-грамматика

<E> ::= <T> <E'>.
<E'> ::= + <T> <E'> | - <T> <E'> | .
<T> ::= <F> <T'>.
<T'> ::= * <F> <T'> | / <F> <T'> | .
<F> ::= <number> | <var> | ( <E> ) | - <F>.


Алгоритм вычисления значения выражения должен быть разбит на две части: лексический анализатор и синтаксический анализатор.

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

type Lexem struct {
Tag
Image string
}

Здесь Image — подстрока арифметического выражения, соответствующая распознанной лексеме, а Tag — целочисленный код, задающий тип лексемы:

type Tag int

const (
ERROR Tag = 1 << iota // Неправильная лексема
NUMBER // Целое число
VAR // Имя переменной
PLUS // Знак +
MINUS // Знак -
MUL // Знак *
DIV // Знак /
LPAREN // Левая круглая скобка
RPAREN // Правая круглая скобка
)


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

if lx.Tag & (PLUS | MINUS) != 0 {
...
}

Лексический анализатор должен выполняться в отдельной go-программе, получающей на вход арифметическое выражение и канал лексем и отправляющей распознанные лексемы в этот канал:

func lexer(expr string, lexems chan Lexem) {
...
}

Синтаксический анализатор должен быть составлен методом рекурсивного спуска по приведённой LL(1)-грамматике.

Программа должна запрашивать у пользователя значения переменных, входящих в выражение, и выводить в стандартный поток вывода значение выражения или сообщение «error», если выражение содержит синтаксическую ошибку. Если некоторая переменная входит в выражение многократно, её значение всё равно должно запрашиваться только один раз.

@golang_interview
Паттерны и практики Go

Слайды + заметки с презентации Abhinav Gupta о нескольких шаблонах и передовых методах, которые вы можете использовать для разработки Go-библиотек, совместимых с предыдущими версиями.
👣 Задача реализовать экспоненциального поиска.

Экспоненциальный поиск — это еще один алгоритм поиска, который может быть достаточно легко реализован на Python, по сравнению с jump search и поиском Фибоначчи, которые немного сложны. Он также известен под названиями galloping search, doubling search и Struzik search.

Экспоненциальный поиск зависит от бинарного поиска для выполнения окончательного сравнения значений. Алгоритм работает следующим образом:

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

Пишите свое решение в комментариях👇


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Что выведет код ?

package main

import "fmt"

func foo(a []int) {
a[1] = 5
}

func bar(a []int) {
for i := 0; i < len(a); i += 2 {
a[i], a[i+1] = a[i+1], a[i]
}
}

func main() {
a := []int{1, 2, 3, 4, 5, 6}
fmt.Printf("a[1]=%d\n", a[1])

foo(a)
fmt.Printf("a[1]=%d\n", a[1]) // что выведет?

bar(a)
fmt.Printf("a=%v\n", a) // печатает весь слайс, что здесь выведет?
}

Ответ

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Практическая задача. Разработать функции для работы с приоритетной очередью

Запрограммировать функции для работы с приоритетной очередью. Очередь запросов формируется согласно приоритету, снятие выполняется подряд, начиная с младших адресов ( то есть с начала очереди).

Очередь должна представлять из себя массив, в котором должен выполняться сдвиг после каждого чтения и сдвиг — после достижения границы памяти, которая выделена для очереди. Приоритет: минимальное значение числового параметра, при совпадении параметров — LIFO.

Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Решаем задачи. Реализуем алгоритм «Посмотри-и-скажи» (Count and Say).

«Посмотри-и-скажи» — это последовательность чисел, начинающаяся следующим образом:

1, 11, 21, 1211, 111221, 312211, 13112221, 1113213211,… (последовательность A005150 в OEIS).

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

Решим задачу с leetcode: https://leetcode.com/problems/count-and-say

Пример1:
Input: n = 1
Output: '1'


Пример2:
Input: n = 4
Output: '1211'
Explanation:
countAndSay(1) = '1'
countAndSay(2) = say '1' = one 1 = '11'
countAndSay(3) = say '11' = two 1's = '21'
countAndSay(4) = say '21' = one 2 + one 1 = '12' + '11' = '1211'


Ограничения:

- 1 <= n <= 30

Решение:

func countAndSay(n int) string {
dp := make([]string, n + 1)
dp[1] = '1'
var current, next string
counter := 1

for i := 2; i <= n; i++ {
current = dp[i - 1]
next = ''

counter = 1

for j := 1; j < len(current); j++ {
if current[j - 1] == current[j] {
counter++
} else {
next += strconv.Itoa(counter) + string(current[j - 1])
counter = 1
}
}

next += strconv.Itoa(counter) + current[len(current) - 1:]

dp[i] = next
}

return dp[n]
}


👉 Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🌀 Заполнение матрицы по спирали

Эта классическая задача часто встречается на собеседованиях и олимпиадах. Рассмотрим несколько способов решения на Python.

На вход программе подаются два натуральных числа n и m. Напишите программу, которая создает матрицу размером n х m, заполнив ее по спирали числами от 1 до n x m. Спираль начинается в левом верхнем углу и закручивается по часовой стрелке.

Пример ввода:

7 6

Пример вывода:

1 2 3 4 5 6
22 23 24 25 26 7
21 36 37 38 27 8
20 35 42 39 28 9
19 34 41 40 29 10
18 33 32 31 30 11
17 16 15 14 13 12


👉 Пишите свое решение в комментариях👇

@golang_interview
⚜️ Тестовое задание avitoTech

Описание задачи

Разработать микросервис для работы с балансом пользователей (баланс, зачисление/списание/перевод средств).

Сервис должен предоставлять HTTP API и принимать/отдавать запросы/ответы в формате JSON. Дополнительно реализовать методы конвертации баланса и получение списка транзакций. Полное описание в TASK.

Реализация
Следование дизайну REST API.
Подход "Чистой Архитектуры" и техника внедрения зависимости.
Работа с фреймворком gin-gonic/gin.
Работа с СУБД Postgres с использованием библиотеки sqlx и написанием SQL запросов.
Конфигурация приложения - библиотека viper.
Запуск из Docker.
Unit/Интеграционное - тестирование уровней обработчикоов, бизнес-логики и взаимодействия с БД с помощью моков - библиотеки testify, mock.

📌 Github

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
⚜️ Тестовое задание стажера в юнит AvitoPRO

Необходимо реализовать сервис на Golang для генерации случайных значений.

Сервис реализует JSON API работающее по HTTP. Каждой генерации присваивать уникальный id, по которому можно получить результат генерации методом retrieve.

Реализовать методы

POST /api/generate/ - генерация случайного значения и его идентификатора
GET /api/retrieve/ - получение зачения по id, которое вернулось в методе generate
Задача может быть решена со следующими усложнениями

возможность задать входные параметры для метода /api/generate/
type - тип возвращаемого случайного значения (строка, число, guid, цифробуквенное, из заданных значений)
длина возвращаемого значения
возможность идемпотентных запросов (несколько запросов с одним requestId вернут то же самое число)
сервис поставляется как Docker образ, опубликованный в публичном репозитории
написать Unit тесты

Способы запуска сервиса
Тестовый запуск http-сервера с помощью CLI

go run cmd/avitornd/avitornd.go
Запуск через Docker-образ

docker build -t avitornd:local -f deployments/docker/avitornd-prod.Dockerfile .
docker run -p 8888:8888 avitornd:local


Запуск из публичного репозитория DockerHub

docker run -p 8888:8888 maintianone/avitornd:latest

Документация к RESTful API

Документация написана по стандарту OASv3 и расположена в директории

api/openapi-spec

🖥 Github

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM