Skip to content

dvcvms/croc_course_java

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

90 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Winter Java School CROC 2022

Данный репозиторий содержит решения задач, выданных при обучении в зимней школе по Java от КРОК.

Автор решений - Волков Максим

Неделя 1

Задача 1

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

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

public class Main {

  static class Point {
    double x;
    double y;
  }

  public static void main(String[] args) {

    Point a = new Point();
    a.x = 0.0;
    a.y = 0.0;

    Point b = new Point();
    b.x = 2.0;
    b.y = 0.0;

    Point c = new Point();
    c.x = 0.0;
    c.y = 2.0;

    // ...
  }
}

Для вычисления площади можно использовать формулу Герона или применить геометрические свойства векторного произведения. Функция извлечения квадратного корня в Java: Math.sqrt(x).

Входные данные

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

Тестовые примеры

Вершина1 Вершина2 Вершина3 Результат
(0,0) (2,0) (0,2) 2
(0,0) (1,0) (0,1) 0.5
(-5,3) (4,-7) (3,14) 89.5
(-5,-15) (-20,-8) (-110,-213) 1852.5

Пример вызова программы

% java ru/croc/task1/Main  
% Введите координату х вершины №1: 0  
% Введите координату y вершины №1: 0  
% Введите координату х вершины №2: 2  
% Введите координату y вершины №2: 0  
% Введите координату х вершины №3: 0  
% Введите координату y вершины №3: 2  
% Площадь треугольника: 2

Если командная строка не видит JAVA - скорее всего необходимо корректно установить переменные окружения (environment variables). См. (пример для java 10, но аналогично для любой другой версии)

Задача 2

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

Человекочитаемый вид:

{целая часть < 1024}.{дробная часть макс. 1 знак} {единица измерения}

Например:

printBytes(23) -> "23.0 B"
printBytes(1024) -> "1.0 KB"
printBytes(53692044905543) -> "48.8 TB"

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

String.format("%.1f", 1.23456);

Входные данные

Число байт.

Тестовые примеры

Число на вход Строка в результате
23 23.0 B
1024 1.0 KB
53692044905543 48.8 TB
5428952 5.2 MB

Пример вызова программы

java ru/croc/task2/Main 23

Неделя 2

Задача 3

Задан массив целых чисел. Необходимо переставить наименьшее из этих чисел в начало массива, а наибольшее - в конец.

Массивы в Java определяются с помощью указания их размера в квадратных скобках:

int[] v = new int[77];

Размер можно не указывать, но тогда нужно определить сами элементы в фигурных скобках:

int[] v = new int[] {6, 28, 1};

Обращаться к элементам можно по индексу:

System.out.println(v[0]); // выводим первый по счету элемент

v[1] = 16; // изменяем значение элемента с индексом 1

Размер массива:

v.length;

Входные данные

Элементы массива, по очереди через пробел. Без экранирующих символов и обозначений начала и конца массива.

Тестовые примеры

Исходный массив Результирующий массив
[6, 28, 1, 17] [1, 17, 6, 28]
[6, 28, 17, 1] [1, 6, 17, 28]
[1, 17, 6, 28] [1, 17, 6, 28]
[28, 6, 17, 1] [1, 6, 17, 28]
[28, 5, 11, 1, 44, 17, 8] [1, 5, 11, 28, 8, 17, 44]

Пример вызова программы

java ru/croc/task3/Main 6 28 1 17

Задача 4

В текстах программ на Java могут использоваться многострочные (/* ... */) и однострочные (// ...) комментарии. Реализовать метод, принимающий на вход строковую переменную - исходный текст программы на Java, вырезающий из этой строки все комментарии и возвращающий результат в виде строки.

public static void main(String[] args) {
  String source = “...”; // test data
  String noComments = removeJavaComments(source);
  System.out.println(noComments);
}

Пример

/*
 * My first ever program in Java!
 */
class Hello { // class body starts here 
  
  /* main method */
  public static void main(String[] args/* we put command line arguments here*/) {
    // this line prints my first greeting to the screen
    System.out.println("Hi!"); // :)
  }
} // the end
// to be continued...

Результат

class Hello {  
  
  
  public static void main(String[] args) {
    
    System.out.println("Hi!"); 
  }
} 

Неделя 3

Задача 5

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

Прямоугольники определяются координатами левого нижнего и правого верхнего углов, а окружности - координатами центра и радиусом. Вся разметка для изображения представляется массивом Annotation[].

В приложении определен класс аннотированного изображения:

class AnnotatedImage {

  private final String imagePath;

  private final Annotation[] annotations;

  public AnnotatedImage(String imagePath, Annotation... annotations) {
    this.imagePath = imagePath;
    this.annotations = annotations;
  }

  public String getImagePath() {
    return this.imagePath;
  }

  public Annotation[] getAnnotations() {
    return this.annotations;
  }
}

Определите класс Annotation для представления данных разметки (подпись + фигура) и классы Figure, Rectangle, Circle для задания размеченных областей.

Переопределите метод toString класса Annotation так, чтобы в результат выводилась информация о полях и вложенных объектах. Формата вывода:

Окружность:

“C (<X0>, <Y0>), <R>: <Подпись>”

Прямоугольник:

“R (<X1>, <Y1>), (<X2>, <Y2>): <Подпись>”

Например:

C (100, 100), 10: Tree

R (100, 100), (150, 200): Car

Задача 6

От пользователей приложения (см. задачу 5) пришел запрос на возможность перемещать уже размеченные области. Для поддержки новой функциональности вам требуется внести несколько изменений:

  1. выбор аннотации по координатам точки (x, y);

В массиве аннотаций требуется найти первую, фигура которой содержит точку с заданными координатами.

Annotation findByPoint(int x, int y) {
  // ...
}
  1. выбор аннотации по шаблону подписи;

В массиве аннотаций требуется найти первую, подпись которой содержит заданную подстроку.

Annotation findByLabel(String label) {
  // ...
}

Определить, содержит ли строка заданную подстроку, можно с помощью метода contains(CharSequence s) класса String.

  1. перемещение фигуры выбранной аннотации на смещение (dx, dy);

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

public interface Movable {
  
  void move(int dx, int dy);
}

Доработайте классы и реализуйте соответствующие методы.

Задача 7

Определить класс, описывающий позицию на шахматной доске 8x8. Данные класса: компоненты x и y, отсчитываемые от левого нижнего угла (x = 0, y = 0 - левая нижняя клетка).

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

Переопределить метод toString(), выводящий координаты позиции в формате <номер колонки в виде буквы от 'a' до 'h'><номер строки, начиная с 1>. Например, позиция с координатами (1, 1) имеет строковое представление "b2".

Реализовать "фабричный метод" конструирования объекта позиции из строкового представления ("b2" -> объект):

static ChessPosition parse(String position) {
  // ...
}

В виде массива строк задана некоторая последовательность позиций на шахматной доске 8x8. Например, "b1", "a3", "c4", "d6". Реализовать метод, проверяющий, что последовательность может быть пройдена фигурой конь в соответствии с правилами хода этой фигуры (буквой "Г"). На вход метод принимает массив объектов класса, определенных в текущей задаче.

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

public class IllegalMoveException extends Exception {
  // ...
}

Тестовые примеры

[in] "g8", "e7", "e6"
[out] "конь так не ходит: e7 -> e6"

[in] "g8", "e7", "c8"
[out] "OK"

Неделя 4

Задача 8

В текстовом файле слова могут быть разделены одним или несколькими пробелами, или символами перевода строки. Необходимо реализовать программу, считающую количество слов в файле и выводящую результат на экран. Путь к файлу задается первым аргументом командной строки (args[0]).

Пример

[in] Забыл Панкрат Кондратьевич домкрат, А без домкрату ну не поднять на тракте трактор.

[out] 13

Задача 9

В виде строки задан относительный путь в файловой системе, в котором:

"." означает текущую директорию; ".." означает родительскую директорию по отношению к текущей; "/" используется в качестве разделителя директорий.

Реализовать функцию, выполняющую "нормализацию" заданного пути, то есть, удаляющую из него лишние директории с учетом переходов "." и "..".

Пример:

[in]

"КРОК/работа/src/./../../универ/../../../мемы/котики"

[out] "../мемы/котики"

Неделя 5

Задача 10

Вы “ответственно” подходите к информационной безопасности и храните свои пароли в файлах в виде MD5-хешей (https://ru.wikipedia.org/wiki/MD5, https://www.baeldung.com/java-md5).

Но, к сожалению, вы забыли и никак не можете вспомнить свой пароль от учетной записи в почте. Хотя у вас остался его хеш 40682260CC011947FC2D0B1A927138C5. Вы точно помните, что пароль состоял из 7 букв латинского алфавита, и что все они были строчными.

Для генерации хеша вы используете функцию hashPassword

private static final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();

private static String toHexString(byte[] bytes) {
  StringBuilder hex = new StringBuilder(bytes.length * 2);
  for (byte b : bytes) {
    hex.append(HEX_DIGITS[(b & 0xff) >> 4]);
    hex.append(HEX_DIGITS[b & 0x0f]);
  }
  return hex.toString();
}

private static String hashPassword(String password) {
  MessageDigest digest;
  try {
    digest = MessageDigest.getInstance("MD5");
  } catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
  }
  digest.update(password.getBytes());
  byte[] bytes = digest.digest();
  return toHexString(bytes);
}

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

Количество потоков - входные данные для программы, задается первым аргументом командной строки. Хеш пароля - вторым аргументом. Найденный пароль печатается в стандартный поток вывода.

Задача 11

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

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

Делать ставки на лот одновременно могут сразу несколько пользователей.

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

Неделя 6

Задача 12

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

Они предоставили вам интерфейс, который внедрили в свой продукт, и попросили написать его реализацию:

import java.util.List;
import java.util.Set;

public interface BlackListFilter {

  /**
   * From the given list of comments removes ones 
   * that contain words from the black list.
   * 
   * @param comments list of comments; every comment 
   *                 is a sequence of words, separated 
   *                 by spaces, punctuation or line breaks   
   * @param blackList list of words that should not 
   *                  be present in a comment
   */
  void filterComments(List<String> comments, Set<String> blackList);
}

Реализуйте интерфейс BlackListFilter.

Задача 13

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

У вас есть два файла:

  1. Список доступных фильмов. Каждая строка содержит числовой идентификатор фильма и его название, разделенные запятой. Например:
1,Мстители: Финал  
2,Хатико  
3,Дюна  
4,Унесенные призраками  
  1. История просмотров по всем пользователям сервиса. Каждая строка файла содержит список идентификаторов фильмов, просмотренных одним человеком за все время пользования сервисом. Идентификаторы разделены запятыми. Например:
2,1,3  
1,4,3  
2,2,2,2,2,3

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

Алгоритм выбора рекомендации:

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

  2. Из отобранных списков исключаются все, которые пользователь уже посмотрел.

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

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

Пример

[in]
2,4

[out]
Дюна

Неделя 7

Задача 14

Вы реализовали фильтрацию комментариев по “черному списку” слов (задача 13) и с чистой совестью ушли в отпуск на 3 недели.

По возвращении из отпуска вы обнаружили, что логика фильтрации усложнилась. Также выяснилось, что нет единого способа представления комментариев среди сервисов: где-то они представлены строками, где-то объектами специализированных классов. Вдобавок некоторым сервисам оказалось неудобным передавать набор комментариев на фильтрацию в виде списка и предпочтительнее коллекция другого типа.

В результате разработчики разных сервисов реализовали копии методов для применения правил “черного списка”, учитывающие специфику их сервисов. А так как правила фильтрации тоже менялись в процессе, эти методы правились не совместно, что привело к плохо читаемому и поддерживаемому коду: логика с одной стороны дублируется, но с другой - работает в каждом методе по-особенному.

Вы берете дело в свои руки и решаете реализовать единый метод фильтрации, учитывающий все обнаруженные особенности. В ходе анализа кода вы отмечаете для себя следующее:

  1. Условия фильтрации в разных сервисах различаются и нет возможности обобщить их в рамках одного метода. Поэтому способ фильтрации вы решаете представлять в виде предиката и позволять определять его вызывающим сервисам.

  2. Набор используемых сервисами классов-представлений для комментариев обширен (String, Comment, CommentDto, …) и, возможно, будет и в дальнейшем расширяться.

  3. Сервисы работают с наборами комментариев в виде коллекций разных типов (HashSet, ArrayList, ArrayDeque, …), но все они имплементируют интерфейс Iterable.

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

Обновите интерфейс BlackListFilter и реализуйте новый механизм фильтрации в виде default-метода.

Задача 15

Государственная организация принимает заявки, на которые необходимо формировать ответ. В формировании ответа участвуют разные отделы организации по следующему принципу:

  • сначала заявка рассматривается корневым отделом;
  • затем она переводится во все его дочернии отделы, в которых рассматривается параллельно;
  • и т.д., пока заявка не пройдет через все отделы.

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

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

Конфигурация отделов задается файлом со следующим форматом строк <код отдела>, <код родительского отдела или “-”, если отдел корневой>, <время обработки заявки в часах>. Например:

A,-,1  
B1,A,3  
C11,B1,1  
C12,B1,1  
B2,A,1  
C21,B2,4  
B3,A,2  
C31,B3,1  
D311,C31,1  

Время обработки заявки для этой конфигурации: 6 часов

Задача 16

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

time message\n,

где time - время в формате POSIX time (количество миллисекунд с 1 января 1970 года), message - произвольный текст.

Строки в логах всегда отсортированы по времени в порядке возрастания.

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

Поэтому вы решили реализовать утилиту слияния нескольких логов в один общий. Утилита в качестве аргумента командной строки принимает путь к директории, в которой находятся файлы логов (возможно, разбитые по вложенным директориям). Результат слияния утилита записывает в стандартный поток вывода в виде общей последовательности строк из всех логов в порядке возрастания времени. Логами считаются файлы с расширениями .log или .trace, все файлы с другими расширениями игнорируются.

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

Бонус

Задача Б1

ЗАМЕТКА: Эта бонусная задача исследовательского типа. Её целью является не просто получение нужного результата, но и самостоятельная реализация подходящих условий для этого. Мы понимаем, что задача немного “грибная” (=с изюминкой), но все-таки и такие задачи бывают в реальной работе.

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

image

ɑ - доля вычислений, которая не может быть распараллелена (выполняется внутри критической секции),
p - количество потоков,
Sp - во сколько раз скорость выполнения в p потоков превышает скорость выполнения в однопоточном режиме.

Вы реализовали алгоритм, ¾ вычислений которого могут быть выполнены параллельно. То есть, ɑ = 0.25. Придумайте и реализуйте приложение, которое в режиме симуляции определит оптимальное количество потоков для этой степени параллелизации (позволяющее получить 90% прироста от возможного теоретического максимума):

image

То есть, min p, для которого Sp >= 0.9 * 4 >= 3.6

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

Неделя 8

Задача 17

Вы разрабатываете бэкенд интернет-магазина. Магазин уже функционирует и принимает заказы. Информация о заказах регистрируется в Excel-таблице вручную. В нее внесены данные за все время существования магазина. Заказчик выгрузил и передал вам эту таблицу в виде CSV-файла.

Формат файла
<номер_заказа:integer>,<логин_пользователя:string>,<артикул_товара:string>,<название_товара:string>,<цена_в_рублях:integer>

Содержимое

1,vasya,Т1,Монитор,500  
1,vasya,Т2,Мышь,50  
2,petya,Т2,Мышь,50  
2,petya,Т2,Мышь,50  
2,petya,Т3,Клавиатура,150  
1,vasya,Т4,Блок питания, 200 
3,nikita,Т4,Блок питания, 200 
4,olga,Т4,Блок питания, 200  
3,nikita,Т5,Видеокарта,15000  
3,nikita,Т5,Видеокарта,15000  
4,olga,Т5,Видеокарта,15000  
4,olga,Т5,Видеокарта,15000  

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

Спроектируйте структуру таблиц для представления информации о заказах в базе данных и загрузите в них данные из файла. Для этого разработайте приложение, которое:

  1. Создаст в базе данных все необходимые таблицы.
  2. Импортирует в базу данных все записи исходного файла.

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

Задача 18

Вы продолжаете разработку бэкенда интернет-магазина. Уже спроектирована схема данных и есть первичное наполнение, следующим шагом вы решаете разработать DAO-класс для работы с базой данных заказов. Для этого вы добавляете в приложение классы сущностей заказа (Order) и товара (Product) и определяетесь с составом необходимых методов DAO-класса:

Product findProduct(String productCode);
Поиск в базе данных товара с указанным артикулом. Если соответствующего товара в базе данных нет, метод возвращает null.

Product createProduct(Product product);
Создание нового товара. Если в базе данных существует товар с переданным артикулом, метод выбрасывает исключение.

Product updateProduct(Product product);
Изменение информации о товаре. Название и цена товара в базе данных заменяется на значения, указанные в полях параметра product. Артикул товара, данные которого должны быть изменены, также задается полем объекта product.

void deleteProduct(String productCode);
Удаление товара и всех упоминаний о нем в заказах. Вас смущает необходимость изменения уже выданных заказов, но заказчик настаивает.

Order createOrder(String userLogin, List products);
Создание заказа. Для указанного пользователя в базе данных создается новый заказ с заданным списком товаров.

Не забудьте протестировать собственное решение (любым способом, можно просто вызывать требуемые методы из main-метода с произвольными параметрами. Реализуйте программу с указанными операциями.

Задача 19

Реализуйте программу, которая печатает/выводит/отправляет строку "Hello, world!" в любое место, кроме консоли. (Записывать символы в стандартный поток вывода запрещено.)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages