Как контролировать уникальные указатели и умножать их ровно один раз в функции double в Go
Что проверяют
Это задача на знание того, что указатели в Go сравнимы и годятся в ключи map. Типичная формулировка: double(nums []*int) получает срез указателей, часть ведёт на одну и ту же переменную, а удвоить каждое значение нужно ровно один раз. Следом спрашивают про сложность и конкурентный вызов.
Как отвечать
Наивный цикл *p *= 2 удвоит переменную столько раз, сколько на неё указателей в срезе. Решение: запоминать обработанные адреса.
func double(nums []*int) {
seen := make(map[*int]struct{}, len(nums))
for _, p := range nums {
if p == nil {
continue
}
if _, ok := seen[p]; ok {
continue
}
seen[p] = struct{}{}
*p *= 2
}
}Что проговорить:
- сравнение указателей:
p1 == p2истинно, когда оба указывают на одну переменную, значения не сравниваются. Две разные переменные со значением 5 удвоятся обе; - *`map[int]struct{}`**: идиоматичное множество, пустая структура не занимает памяти под значение;
- сложность: O(n) по времени и памяти против O(n²) у вложенного цикла;
nil: разыменование вызовет панику, такие элементы пропускают или возвращают ошибку, это стоит уточнить у интервьюера.
Про конкурентность: две горутины, удваивающие одну переменную, это гонка данных, её покажет go test -race. Нужен sync.Mutex или разделение данных между горутинами.
Где спотыкаются
Кладут в карту значение *p вместо адреса. Две разные переменные с одинаковым числом сливаются в одну, и вторая остаётся неудвоенной.
Пишут вложенный цикл «встречался ли этот указатель раньше». Работает, но за O(n²), и интервьюер попросит улучшить.
Помечают обработанные элементы, обнуляя их в срезе. Функция портит входные данные, которые вызывающий код ещё собирается использовать.