diff --git a/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md b/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md
new file mode 100644
index 0000000..48ddd62
--- /dev/null
+++ b/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md
@@ -0,0 +1,646 @@
+
+
+## 📝 Задача: Система управления событиями
+
+### **Условие:**
+
+Вы разрабатываете систему для управления событиями (конференции, вебинары, встречи). Нужно реализовать сервис регистрации участников с учетом следующих требований:
+
+1. **Событие** имеет:
+
+ - ID, название, описание
+ - Дату начала и окончания
+ - Максимальное количество участников
+ - Статус (DRAFT, PUBLISHED, CANCELLED)
+2. **Участник** имеет:
+
+ - ID, имя, email
+ - Дату регистрации
+3. **Бизнес-правила:**
+
+ - Регистрация возможна только на опубликованные события
+ - Нельзя зарегистрироваться на событие, которое уже началось
+ - Нельзя превысить лимит участников
+ - Один участник может зарегистрироваться на событие только один раз
+ - При отмене события нужно уведомить всех участников
+
+### **Техническое задание:**
+
+Реализуйте следующие компоненты:
+
+1. **Entity классы** (Event, Participant, Registration)
+
+2. **Repository интерфейсы**
+
+3. **Service класс EventRegistrationService** с методами:
+
+ - `registerParticipant(Long eventId, Long participantId)`
+ - `cancelRegistration(Long eventId, Long participantId)`
+ - `cancelEvent(Long eventId)`
+ - `getEventParticipants(Long eventId)`
+4. **REST Controller** с endpoint'ами для регистрации
+
+5. **Обработка исключений** для всех бизнес-правил
+
+
+### **Дополнительные требования:**
+
+- Использовать Spring Boot, JPA/Hibernate
+- Добавить валидацию данных
+- Написать unit-тесты для сервиса
+- Подумать о транзакциях и concurrency
+
+**Время на выполнение:** 25 минут
+
+---
+
+# 🧮 Алгоритмическая задача для Middle разработчика
+
+## 📝 Задача: Планировщик встреч
+
+### **Условие:**
+
+У вас есть список встреч, каждая встреча представлена как массив `[start, end]`, где `start` и `end` - время начала и окончания в минутах от начала дня.
+
+Нужно найти максимальное количество непересекающихся встреч, которые можно провести в одной переговорной комнате.
+
+### **Примеры:**
+
+**Пример 1:**
+
+```
+Ввод: meetings = [[0,30],[5,10],[15,20]]
+Вывод: 2
+Объяснение: Можно выбрать встречи [0,30] и [15,20] ИЛИ [5,10] и [15,20]
+```
+
+**Пример 2:**
+
+```
+Ввод: meetings = [[7,10],[2,4]]
+Вывод: 2
+Объяснение: Обе встречи не пересекаются
+```
+
+**Пример 3:**
+
+```
+Ввод: meetings = [[1,5],[8,9],[8,9],[5,9],[9,15]]
+Вывод: 3
+Объяснение: Можно выбрать [1,5], [8,9], [9,15]
+```
+
+### **Ограничения:**
+
+- `1 <= meetings.length <= 10^4`
+- `meetings[i].length == 2`
+- `0 <= starti < endi <= 10^6`
+
+### **Задание:**
+
+1. Реализуйте метод `public int maxMeetings(int[][] meetings)`
+2. Объясните алгоритм и его сложность
+3. Напишите unit-тесты
+
+**Время на выполнение:** 15 минут
+
+---
+
+# ✅ Решения задач
+
+## 💼 Решение прикладной задачи
+
+ Показать решение
+
+### **1. Entity классы:**
+
+```java
+@Entity
+@Table(name = "events")
+public class Event {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ private String description;
+
+ @Column(name = "start_date", nullable = false)
+ private LocalDateTime startDate;
+
+ @Column(name = "end_date", nullable = false)
+ private LocalDateTime endDate;
+
+ @Column(name = "max_participants", nullable = false)
+ private Integer maxParticipants;
+
+ @Enumerated(EnumType.STRING)
+ private EventStatus status;
+
+ @OneToMany(mappedBy = "event", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+ private List registrations = new ArrayList<>();
+
+ // конструкторы, геттеры, сеттеры
+}
+
+@Entity
+@Table(name = "participants")
+public class Participant {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(nullable = false)
+ private String name;
+
+ @Column(nullable = false, unique = true)
+ private String email;
+
+ // конструкторы, геттеры, сеттеры
+}
+
+@Entity
+@Table(name = "registrations")
+public class Registration {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "event_id", nullable = false)
+ private Event event;
+
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "participant_id", nullable = false)
+ private Participant participant;
+
+ @Column(name = "registration_date", nullable = false)
+ private LocalDateTime registrationDate;
+
+ // конструкторы, геттеры, сеттеры
+}
+
+public enum EventStatus {
+ DRAFT, PUBLISHED, CANCELLED
+}
+```
+
+### **2. Repository интерфейсы:**
+
+```java
+@Repository
+public interface EventRepository extends JpaRepository {
+ List findByStatus(EventStatus status);
+}
+
+@Repository
+public interface ParticipantRepository extends JpaRepository {
+ Optional findByEmail(String email);
+}
+
+@Repository
+public interface RegistrationRepository extends JpaRepository {
+ boolean existsByEventIdAndParticipantId(Long eventId, Long participantId);
+
+ Optional findByEventIdAndParticipantId(Long eventId, Long participantId);
+
+ @Query("SELECT r.participant FROM Registration r WHERE r.event.id = :eventId")
+ List findParticipantsByEventId(@Param("eventId") Long eventId);
+
+ long countByEventId(Long eventId);
+
+ void deleteByEventId(Long eventId);
+}
+```
+
+### **3. Service класс:**
+
+```java
+@Service
+@Transactional
+public class EventRegistrationService {
+
+ private final EventRepository eventRepository;
+ private final ParticipantRepository participantRepository;
+ private final RegistrationRepository registrationRepository;
+ private final NotificationService notificationService;
+
+ public EventRegistrationService(EventRepository eventRepository,
+ ParticipantRepository participantRepository,
+ RegistrationRepository registrationRepository,
+ NotificationService notificationService) {
+ this.eventRepository = eventRepository;
+ this.participantRepository = participantRepository;
+ this.registrationRepository = registrationRepository;
+ this.notificationService = notificationService;
+ }
+
+ public void registerParticipant(Long eventId, Long participantId) {
+ Event event = eventRepository.findById(eventId)
+ .orElseThrow(() -> new EventNotFoundException("Event not found: " + eventId));
+
+ Participant participant = participantRepository.findById(participantId)
+ .orElseThrow(() -> new ParticipantNotFoundException("Participant not found: " + participantId));
+
+ validateRegistration(event, participant);
+
+ Registration registration = new Registration();
+ registration.setEvent(event);
+ registration.setParticipant(participant);
+ registration.setRegistrationDate(LocalDateTime.now());
+
+ registrationRepository.save(registration);
+ }
+
+ private void validateRegistration(Event event, Participant participant) {
+ // Проверка статуса события
+ if (event.getStatus() != EventStatus.PUBLISHED) {
+ throw new RegistrationException("Event is not published");
+ }
+
+ // Проверка даты начала
+ if (event.getStartDate().isBefore(LocalDateTime.now())) {
+ throw new RegistrationException("Event has already started");
+ }
+
+ // Проверка лимита участников
+ long currentParticipants = registrationRepository.countByEventId(event.getId());
+ if (currentParticipants >= event.getMaxParticipants()) {
+ throw new RegistrationException("Event is full");
+ }
+
+ // Проверка дублирования регистрации
+ if (registrationRepository.existsByEventIdAndParticipantId(event.getId(), participant.getId())) {
+ throw new RegistrationException("Participant already registered for this event");
+ }
+ }
+
+ public void cancelRegistration(Long eventId, Long participantId) {
+ Registration registration = registrationRepository.findByEventIdAndParticipantId(eventId, participantId)
+ .orElseThrow(() -> new RegistrationNotFoundException("Registration not found"));
+
+ registrationRepository.delete(registration);
+ }
+
+ public void cancelEvent(Long eventId) {
+ Event event = eventRepository.findById(eventId)
+ .orElseThrow(() -> new EventNotFoundException("Event not found: " + eventId));
+
+ List participants = registrationRepository.findParticipantsByEventId(eventId);
+
+ // Отмена события
+ event.setStatus(EventStatus.CANCELLED);
+ eventRepository.save(event);
+
+ // Уведомление участников
+ participants.forEach(participant ->
+ notificationService.notifyEventCancellation(participant, event));
+ }
+
+ @Transactional(readOnly = true)
+ public List getEventParticipants(Long eventId) {
+ if (!eventRepository.existsById(eventId)) {
+ throw new EventNotFoundException("Event not found: " + eventId);
+ }
+
+ return registrationRepository.findParticipantsByEventId(eventId);
+ }
+}
+```
+
+### **4. REST Controller:**
+
+```java
+@RestController
+@RequestMapping("/api/events")
+@Validated
+public class EventRegistrationController {
+
+ private final EventRegistrationService registrationService;
+
+ public EventRegistrationController(EventRegistrationService registrationService) {
+ this.registrationService = registrationService;
+ }
+
+ @PostMapping("/{eventId}/participants/{participantId}")
+ public ResponseEntity registerParticipant(
+ @PathVariable @Positive Long eventId,
+ @PathVariable @Positive Long participantId) {
+
+ registrationService.registerParticipant(eventId, participantId);
+ return ResponseEntity.ok().build();
+ }
+
+ @DeleteMapping("/{eventId}/participants/{participantId}")
+ public ResponseEntity cancelRegistration(
+ @PathVariable @Positive Long eventId,
+ @PathVariable @Positive Long participantId) {
+
+ registrationService.cancelRegistration(eventId, participantId);
+ return ResponseEntity.ok().build();
+ }
+
+ @DeleteMapping("/{eventId}")
+ public ResponseEntity cancelEvent(@PathVariable @Positive Long eventId) {
+ registrationService.cancelEvent(eventId);
+ return ResponseEntity.ok().build();
+ }
+
+ @GetMapping("/{eventId}/participants")
+ public ResponseEntity> getEventParticipants(
+ @PathVariable @Positive Long eventId) {
+
+ List participants = registrationService.getEventParticipants(eventId);
+ List dtos = participants.stream()
+ .map(this::toDto)
+ .collect(Collectors.toList());
+
+ return ResponseEntity.ok(dtos);
+ }
+
+ private ParticipantDto toDto(Participant participant) {
+ return new ParticipantDto(participant.getId(), participant.getName(), participant.getEmail());
+ }
+}
+```
+
+### **5. Exception Handling:**
+
+```java
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(EventNotFoundException.class)
+ public ResponseEntity handleEventNotFound(EventNotFoundException ex) {
+ ErrorResponse error = new ErrorResponse("EVENT_NOT_FOUND", ex.getMessage());
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
+ }
+
+ @ExceptionHandler(RegistrationException.class)
+ public ResponseEntity handleRegistrationError(RegistrationException ex) {
+ ErrorResponse error = new ErrorResponse("REGISTRATION_ERROR", ex.getMessage());
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleValidation(ConstraintViolationException ex) {
+ ErrorResponse error = new ErrorResponse("VALIDATION_ERROR", "Invalid input parameters");
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(error);
+ }
+}
+```
+
+### **6. Unit тесты:**
+
+```java
+@ExtendWith(MockitoExtension.class)
+class EventRegistrationServiceTest {
+
+ @Mock
+ private EventRepository eventRepository;
+
+ @Mock
+ private ParticipantRepository participantRepository;
+
+ @Mock
+ private RegistrationRepository registrationRepository;
+
+ @Mock
+ private NotificationService notificationService;
+
+ @InjectMocks
+ private EventRegistrationService service;
+
+ @Test
+ void registerParticipant_Success() {
+ // Given
+ Long eventId = 1L;
+ Long participantId = 1L;
+
+ Event event = createPublishedEvent();
+ Participant participant = createParticipant();
+
+ when(eventRepository.findById(eventId)).thenReturn(Optional.of(event));
+ when(participantRepository.findById(participantId)).thenReturn(Optional.of(participant));
+ when(registrationRepository.countByEventId(eventId)).thenReturn(5L);
+ when(registrationRepository.existsByEventIdAndParticipantId(eventId, participantId)).thenReturn(false);
+
+ // When
+ service.registerParticipant(eventId, participantId);
+
+ // Then
+ verify(registrationRepository).save(any(Registration.class));
+ }
+
+ @Test
+ void registerParticipant_EventNotPublished_ThrowsException() {
+ // Given
+ Event event = createDraftEvent();
+ Participant participant = createParticipant();
+
+ when(eventRepository.findById(1L)).thenReturn(Optional.of(event));
+ when(participantRepository.findById(1L)).thenReturn(Optional.of(participant));
+
+ // When & Then
+ assertThrows(RegistrationException.class,
+ () -> service.registerParticipant(1L, 1L));
+ }
+
+ @Test
+ void registerParticipant_EventFull_ThrowsException() {
+ // Given
+ Event event = createPublishedEvent();
+ event.setMaxParticipants(10);
+ Participant participant = createParticipant();
+
+ when(eventRepository.findById(1L)).thenReturn(Optional.of(event));
+ when(participantRepository.findById(1L)).thenReturn(Optional.of(participant));
+ when(registrationRepository.countByEventId(1L)).thenReturn(10L);
+
+ // When & Then
+ assertThrows(RegistrationException.class,
+ () -> service.registerParticipant(1L, 1L));
+ }
+
+ private Event createPublishedEvent() {
+ Event event = new Event();
+ event.setId(1L);
+ event.setStatus(EventStatus.PUBLISHED);
+ event.setStartDate(LocalDateTime.now().plusDays(1));
+ event.setMaxParticipants(10);
+ return event;
+ }
+
+ private Event createDraftEvent() {
+ Event event = new Event();
+ event.setId(1L);
+ event.setStatus(EventStatus.DRAFT);
+ event.setStartDate(LocalDateTime.now().plusDays(1));
+ event.setMaxParticipants(10);
+ return event;
+ }
+
+ private Participant createParticipant() {
+ Participant participant = new Participant();
+ participant.setId(1L);
+ participant.setName("John Doe");
+ participant.setEmail("john@example.com");
+ return participant;
+ }
+}
+```
+
+
+
+---
+
+## 🧮 Решение алгоритмической задачи
+
+ Показать решение
+
+### **Основная идея:**
+
+Это классическая задача о максимальном количестве непересекающихся интервалов. Используем жадный алгоритм:
+
+1. Сортируем встречи по времени окончания
+2. Выбираем встречу с самым ранним окончанием
+3. Исключаем все пересекающиеся с ней встречи
+4. Повторяем для оставшихся встреч
+
+### **Решение:**
+
+```java
+import java.util.*;
+
+public class MeetingScheduler {
+
+ public int maxMeetings(int[][] meetings) {
+ if (meetings == null || meetings.length == 0) {
+ return 0;
+ }
+
+ // Сортируем по времени окончания
+ Arrays.sort(meetings, (a, b) -> Integer.compare(a[1], b[1]));
+
+ int count = 0;
+ int lastEndTime = -1;
+
+ for (int[] meeting : meetings) {
+ int startTime = meeting[0];
+ int endTime = meeting[1];
+
+ // Если текущая встреча не пересекается с предыдущей выбранной
+ if (startTime >= lastEndTime) {
+ count++;
+ lastEndTime = endTime;
+ }
+ }
+
+ return count;
+ }
+}
+```
+
+### **Объяснение алгоритма:**
+
+1. **Сортировка:** Сортируем все встречи по времени окончания. Это ключевая идея - выбирая встречи с самым ранним окончанием, мы оставляем максимум времени для последующих встреч.
+
+2. **Жадный выбор:** Проходим по отсортированным встречам и выбираем те, которые не пересекаются с уже выбранными.
+
+3. **Условие непересечения:** Встреча не пересекается с предыдущей, если её время начала >= времени окончания предыдущей.
+
+
+### **Временная сложность:** O(n log n) - из-за сортировки
+
+### **Пространственная сложность:** O(1) - если не считать пространство для сортировки
+
+### **Пошаговый пример:**
+
+Для `meetings = [[1,5],[8,9],[8,9],[5,9],[9,15]]`:
+
+1. После сортировки по времени окончания: `[[1,5], [8,9], [8,9], [5,9], [9,15]]`
+2. Выбираем `[1,5]`, `lastEndTime = 5`
+3. Проверяем `[8,9]`: `8 >= 5` ✓, выбираем, `lastEndTime = 9`
+4. Проверяем `[8,9]`: `8 < 9` ✗, пропускаем
+5. Проверяем `[5,9]`: `5 < 9` ✗, пропускаем
+6. Проверяем `[9,15]`: `9 >= 9` ✓, выбираем
+7. Результат: 3 встречи
+
+### **Unit тесты:**
+
+```java
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+class MeetingSchedulerTest {
+
+ private final MeetingScheduler scheduler = new MeetingScheduler();
+
+ @Test
+ void testExample1() {
+ int[][] meetings = {{0,30},{5,10},{15,20}};
+ assertEquals(2, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testExample2() {
+ int[][] meetings = {{7,10},{2,4}};
+ assertEquals(2, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testExample3() {
+ int[][] meetings = {{1,5},{8,9},{8,9},{5,9},{9,15}};
+ assertEquals(3, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testEmptyInput() {
+ int[][] meetings = {};
+ assertEquals(0, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testNullInput() {
+ assertEquals(0, scheduler.maxMeetings(null));
+ }
+
+ @Test
+ void testSingleMeeting() {
+ int[][] meetings = {{1,3}};
+ assertEquals(1, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testAllOverlapping() {
+ int[][] meetings = {{1,4},{2,5},{3,6}};
+ assertEquals(1, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testNoOverlapping() {
+ int[][] meetings = {{1,2},{3,4},{5,6}};
+ assertEquals(3, scheduler.maxMeetings(meetings));
+ }
+
+ @Test
+ void testTouchingMeetings() {
+ int[][] meetings = {{1,3},{3,5},{5,7}};
+ assertEquals(3, scheduler.maxMeetings(meetings));
+ }
+}
+```
+
+### **Альтернативные подходы:**
+
+1. **Dynamic Programming:** Сложность O(n²), не оптимально для этой задачи
+2. **Recursive with memoization:** Также O(n²), избыточно
+3. **Priority Queue:** Можно использовать, но жадный алгоритм проще и эффективнее
+
+### **Почему жадный алгоритм работает:**
+
+Выбирая встречу с самым ранним окончанием, мы всегда оставляем максимально возможное время для размещения остальных встреч. Это оптимальная стратегия для данной задачи.
+
+
\ No newline at end of file