Йо, меня зовут Наби, мне 23 года. Заранее благодарю за чтение и желаю продуктивно провести время! Если после прочтения возникнут вопросы, пожелания или предложения, то буду рад ознакомиться со всем в комментариях!
Предисловие
Не так давно я захотел попробовать порешать задачи по программированию, но не знал, с чего начать, где лучше решать, на чём лучше решать и т.д.
До этого у меня не было опыта решения чисто алгоритмических задач, да и в целом никогда не было необходимости. В работе всегда решал проблемы интуитивно, импровизировал в моменте, не зная какие-то конкретные алгоритмы или более эффективные способы решения проблемы. С одной стороны, я всегда считал это плюсом, но с другой мне всегда казалось, что я мог бы решить вопрос быстрее или эффективнее, чтобы в будущем не возникало проблем.
И, собственно, вот так я и пришёл к решению начать эту рубрику статей, в которой я буду рассказывать о своем опыте, о новых вещах, которые сам выучил в процессе решения задач, объяснять их решения (насколько буду в состоянии это сделать). Плюс хочется, чтобы и другие смогли присоединиться ко мне, поделиться своим опытом и высказать свои мысли и идеи!
Выбор платформы с задачами
В первую очередь на глаза попалась платформа LeetCode.
Если почитать Вики, то можно понять, что основное предназначение платформы это подготовка к техническим интервью и развитие навыков программирования.
Задач огромное количество на абсолютно разные тематики, они же тут являются Тэгами
Языков программирования тоже очень много. Конкретно я использовал Python, когда тестировал платформу.
В нашем с вами случае это не имеет значения, всю рубрику мы будем решать задачи чисто на 1С. Забегая наперёд, также уточню, что я хочу сделать какую-нибудь конфигурацию для хранения и решения задач. Чтобы она как минимум умела оценивать время исполнения и затраченные ресурсы задачи, а в дальнейшем подключить к ней какую-нибудь нейросеть, чтобы получать более обширную оценку кода. Надеюсь услышать ваши предложения по этому вопросу, возможно, у нас получится объединить силы и сделать что-то интересное. В перспективе даже можно было бы какой-нибудь онлайн сервис запустить с интерпретатором 1С и задачами, что-то типа 1Совского аналога всем этим сервисам!
Ну да ладно, я отошёл от темы. Также из интересного я обратил внимание на то, что на сайте есть возможность отфильтровать задачи по компаниям, где эти задачи якобы используются
На этом в принципе всё, что-то дополнительно выделить нечего!
Вторым сервисом, который я выбрал, является CodeWars
В отличие от предыдущего сервиса, CodeWars не подразумевает подготовку к интервью. Оно также бросается в глаза, когда понимаешь отсутствие возможности фильтровать по компаниям, как это было у предыдущего сервиса.
Из примечательного стоит выделить огромное количество и разнообразие тэгов, наверное, в несколько раз больше чем у предыдущего сервиса
Ну и, конечно, самая интересная деталь это система оценки твоих навыков. Тут единицей измерения скилла является так называется Честь (Honor), на основании которой рассчитывается твой Ранг. Задача, она же проблема, тут называется по другому, интересное слово "Ката". Я полагаю, это отсылка к Дзюдо или Карате, где также используется это слово для описания уровня упражнений.
Что касаемо рангов, тут их восемь
Да и в целом по этому сервису также всё. Больше добавить нечего, в процессе будем искать задачи и там, и там!
Где будем решать и тестировать задачи?
Как я и упоминал ранее, я решил начать делать конфигурацию чисто для решения алгоритмических задач. Чтобы можно было удобно и быстро менять код, сохранять задачи, сохранять решения, анализировать их и прочее. Всё сразу сделать невозможно, начнем с минимума и постепенно будем улучшать.
Вот страница проекта на Github (нажмите на выделенный текст), можете заранее добавить себе в избранное, чтобы не потерять и в дальнейшем следить за обновлениями.
На данном этапе конфигурация представляет из себя обычную форму с двумя многострочными полями и кнопкой для запуска кода
Принцип работы на данном этапе максимально простой, кнопка отправляет строку из поля "Код" на серверную функцию, которая выполняет код и возвращает результат
//Код кнопки
РезультатИсполнения = РаботаСКодомСервер.ИсполнитьКод(Код);
Вывод = РезультатИсполнения.Вывод;
ВремяИсполненияСтрока = Строка((РезультатИсполнения.ВремяКонец - РезультатИсполнения.ВремяНачало)/1000) + " сек.";
ПредупреждениеАсинх(ВремяИсполненияСтрока,0,"Время исполнения");
//Функция исполнения кода в общем серверном модуле
Функция ИсполнитьКод(Код) Экспорт
Результат = Новый Структура;
//
Попытка
Результат.Вставить("ВремяНачало",ТекущаяУниверсальнаяДатаВМиллисекундах());
//
Вывод = Неопределено;
Выполнить(Код);
//
Результат.Вставить("ВремяКонец",ТекущаяУниверсальнаяДатаВМиллисекундах());
Результат.Вставить("Вывод",Вывод);
Исключение
Результат.Вставить("Вывод",ИнформацияОбОшибке().Причина.Описание);
КонецПопытки;
//
Возврат Результат;
КонецФункции
Как видим, код выполняется, считается время исполнения и затем возвращается результат, который выводится на второе поле на форме. Главное - записать результат выполнения кода в переменную "Вывод".
Попробуем выполнить что-нибудь:
Как видим, цикл исполнился, последнее значения записалось в переменную "Вывод", и данные из этой переменной отправились на форму. Ну и затем вывелось предупреждение со временем исполнения. Само собой, время исполнения может быть разное относительно каждого компьютера, поэтому единственный способ оценить эффективность решения - это сравнить собственные решения на своём же компьютере. Возможно, в будущем придумаем какое-нибудь серверное решение для сравнения результатов друг друга!
Ну что ж, приступим уже к самим задачам, на данном этапе у нас есть всё как минимум для того, чтобы начать!
Задачи и их решения
Задача 1
Платформа: LeetCode
Название задачи: Two Sum
Ссылка на задачу: https://leetcode.com/problems/two-sum/description/
Оригинальное описание задачи
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
Constraints:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
Only one valid answer exists.
Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?
В чём суть? Дан неупорядоченный массив из чисел (Nums) и одно целевое число (Target). Нужно в этом массиве найти 2 элемента, сумма которых даст целевое число. Результатом должен быть массив из двух индексов элементов оригинального массива
Решение
Первое, что приходит на ум, само собой брутфорс. Запускаем цикл, внутри каждой итерации также запускаем цикл и суммируем текущие элементы. Если они будут равны, сохраняем индексы в новый массив и возвращаем. Давайте попробуем поработать с примерами, описанными в оригинальном описании задачи.
ОригинальныйМассив = Новый Массив;
ОригинальныйМассив.Добавить(3);
ОригинальныйМассив.Добавить(2);
ОригинальныйМассив.Добавить(4);
ЦелевоеЧисло = 6;
//
ПервыйИндекс = Неопределено;
ВторойИндекс = Неопределено;
//
Для НомерСтроки = 1 По ОригинальныйМассив.Количество() Цикл
Для НомерПодСтроки = 1 По ОригинальныйМассив.Количество() Цикл
Если НомерСтроки <> НомерПодСтроки Тогда
Если ОригинальныйМассив[НомерСтроки-1] + ОригинальныйМассив[НомерПодСтроки-1] = ЦелевоеЧисло Тогда
ПервыйИндекс = НомерПодСтроки-1;
ВторойИндекс = НомерСтроки-1;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
//
Вывод = "["+Строка(ПервыйИндекс)+","+Строка(ВторойИндекс)+"]";
В итоге получился вот такой код. Все входные данные из описания успешно проходятся, ответы соответствуют ответам из примера!
Для дополнительной проверки советую попробовать с рандомными массивами!
Задача 2
Платформа: LeetCode
Название задачи: Two Numbers
Ссылка на задачу: https://leetcode.com/problems/add-two-numbers/
Оригинальное описание задачи
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.
Example 2:
Input: l1 = [0], l2 = [0]
Output: [0]
Example 3:
Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
Constraints:
The number of nodes in each linked list is in the range [1, 100].
0 <= Node.val <= 9
It is guaranteed that the list represents a number that does not have leading zeros.
В чём суть? Объясняю. Даны 2 числовых массива, каждый элемент массива может быть только простой цифрой от 1 до 9.
Каждый массив представляет собой перевёрнутое число разбитое на элементы. Например, если дан массив [2, 4, 3] то это означает, что изначально это было число 342. Также и со вторым массивом. Так вот, суть задачи заключается в том чтобы привести эти массивы к исходным формам, прибавить друг к другу и после выполнить те же операции с новым числом. То есть обратить его, разбить на элементы и занести в массив. Ну что ж, начнём?
Решение
В первую очередь подумаем, как вернуть числа к их исходным формам. Для это я бы предложил просто перебрать массив и каждый элемент в виде строки заносить в переменную но в обратном порядке. То бишь если это первая итерация цикла, то закидываем последний элемент массива. В итоге получим 2 строковые переменные, которые легко обращаем в числа. Затем прибавляем друг к другу, превращаем обратно в строку и начинаем уже обращать и разбивать с помощью цикла и функции Сред. Каждый элемент будем после превращать в число и закидывать в массив. Давайте попробуем
ПервыйМассив = Новый Массив;
ПервыйМассив.Добавить(2);
ПервыйМассив.Добавить(4);
ПервыйМассив.Добавить(3);
//
ВторойМассив = Новый Массив;
ВторойМассив.Добавить(5);
ВторойМассив.Добавить(6);
ВторойМассив.Добавить(4);
//
ТретийМассив = Новый Массив;
//
ПервоеЧисло = "";
ВтороеЧисло = "";
//
Для НомерСтроки = 1 По ПервыйМассив.Количество() Цикл
ПервоеЧисло = ПервоеЧисло + Строка(ПервыйМассив[ПервыйМассив.Количество() - НомерСтроки]);
КонецЦикла;
//
Для НомерСтроки = 1 По ВторойМассив.Количество() Цикл
ВтороеЧисло = ВтороеЧисло + Строка(ВторойМассив[ВторойМассив.Количество() - НомерСтроки]);
КонецЦикла;
//
ТретьеЧисло = Строка(Число(ПервоеЧисло) + Число(ВтороеЧисло));
//
Для НомерСтроки = 1 По СтрДлина(ТретьеЧисло) Цикл
ТретийМассив.Добавить(Сред(ТретьеЧисло,СтрДлина(ТретьеЧисло) - НомерСтроки+1,1));
КонецЦикла;
//
Вывод = "[";
Для Каждого Стр Из ТретийМассив Цикл
Вывод = Вывод + Строка(Стр) + ",";
КонецЦикла;
//
Вывод = Лев(Вывод,СтрДлина(Вывод)-1);
Вывод = Вывод + "]"
В итоге получился вот такой код. Все входные данные из описания успешно проходятся, ответы соответствуют ответам из примера!
Для дополнительной проверки советую попробовать с рандомными массивами!
Заключение
Платформа: LeetCode
Название задачи: Two Sum
Ссылка на задачу: https://leetcode.com/problems/two-sum/description/
Оригинальное описание задачи
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
Example 1:
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
Example 2:
Input: nums = [3,2,4], target = 6
Output: [1,2]
Example 3:
Input: nums = [3,3], target = 6
Output: [0,1]
Constraints:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
Only one valid answer exists.
Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?
В чём суть? Дан неупорядоченный массив из чисел (Nums) и одно целевое число (Target). Нужно в этом массиве найти 2 элемента, сумма которых даст целевое число. Результатом должен быть массив из двух индексов элементов оригинального массива
Решение
Первое, что приходит на ум, само собой брутфорс. Запускаем цикл, внутри каждой итерации также запускаем цикл и суммируем текущие элементы. Если они будут равны, сохраняем индексы в новый массив и возвращаем. Давайте попробуем поработать с примерами, описанными в оригинальном описании задачи.
ОригинальныйМассив = Новый Массив;
ОригинальныйМассив.Добавить(3);
ОригинальныйМассив.Добавить(2);
ОригинальныйМассив.Добавить(4);
ЦелевоеЧисло = 6;
//
ПервыйИндекс = Неопределено;
ВторойИндекс = Неопределено;
//
Для НомерСтроки = 1 По ОригинальныйМассив.Количество() Цикл
Для НомерПодСтроки = 1 По ОригинальныйМассив.Количество() Цикл
Если НомерСтроки <> НомерПодСтроки Тогда
Если ОригинальныйМассив[НомерСтроки-1] + ОригинальныйМассив[НомерПодСтроки-1] = ЦелевоеЧисло Тогда
ПервыйИндекс = НомерПодСтроки-1;
ВторойИндекс = НомерСтроки-1;
Прервать;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЦикла;
//
Вывод = "["+Строка(ПервыйИндекс)+","+Строка(ВторойИндекс)+"]";
В итоге получился вот такой код. Все входные данные из описания успешно проходятся, ответы соответствуют ответам из примера!
Для дополнительной проверки советую попробовать с рандомными массивами!
Платформа: LeetCode
Название задачи: Two Numbers
Ссылка на задачу: https://leetcode.com/problems/add-two-numbers/
Оригинальное описание задачи
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.
Example 2:
Input: l1 = [0], l2 = [0]
Output: [0]
Example 3:
Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
Constraints:
The number of nodes in each linked list is in the range [1, 100].
0 <= Node.val <= 9
It is guaranteed that the list represents a number that does not have leading zeros.
В чём суть? Объясняю. Даны 2 числовых массива, каждый элемент массива может быть только простой цифрой от 1 до 9.
Каждый массив представляет собой перевёрнутое число разбитое на элементы. Например, если дан массив [2, 4, 3] то это означает, что изначально это было число 342. Также и со вторым массивом. Так вот, суть задачи заключается в том чтобы привести эти массивы к исходным формам, прибавить друг к другу и после выполнить те же операции с новым числом. То есть обратить его, разбить на элементы и занести в массив. Ну что ж, начнём?
Решение
В первую очередь подумаем, как вернуть числа к их исходным формам. Для это я бы предложил просто перебрать массив и каждый элемент в виде строки заносить в переменную но в обратном порядке. То бишь если это первая итерация цикла, то закидываем последний элемент массива. В итоге получим 2 строковые переменные, которые легко обращаем в числа. Затем прибавляем друг к другу, превращаем обратно в строку и начинаем уже обращать и разбивать с помощью цикла и функции Сред. Каждый элемент будем после превращать в число и закидывать в массив. Давайте попробуем
ПервыйМассив = Новый Массив;
ПервыйМассив.Добавить(2);
ПервыйМассив.Добавить(4);
ПервыйМассив.Добавить(3);
//
ВторойМассив = Новый Массив;
ВторойМассив.Добавить(5);
ВторойМассив.Добавить(6);
ВторойМассив.Добавить(4);
//
ТретийМассив = Новый Массив;
//
ПервоеЧисло = "";
ВтороеЧисло = "";
//
Для НомерСтроки = 1 По ПервыйМассив.Количество() Цикл
ПервоеЧисло = ПервоеЧисло + Строка(ПервыйМассив[ПервыйМассив.Количество() - НомерСтроки]);
КонецЦикла;
//
Для НомерСтроки = 1 По ВторойМассив.Количество() Цикл
ВтороеЧисло = ВтороеЧисло + Строка(ВторойМассив[ВторойМассив.Количество() - НомерСтроки]);
КонецЦикла;
//
ТретьеЧисло = Строка(Число(ПервоеЧисло) + Число(ВтороеЧисло));
//
Для НомерСтроки = 1 По СтрДлина(ТретьеЧисло) Цикл
ТретийМассив.Добавить(Сред(ТретьеЧисло,СтрДлина(ТретьеЧисло) - НомерСтроки+1,1));
КонецЦикла;
//
Вывод = "[";
Для Каждого Стр Из ТретийМассив Цикл
Вывод = Вывод + Строка(Стр) + ",";
КонецЦикла;
//
Вывод = Лев(Вывод,СтрДлина(Вывод)-1);
Вывод = Вывод + "]"
В итоге получился вот такой код. Все входные данные из описания успешно проходятся, ответы соответствуют ответам из примера!
Для дополнительной проверки советую попробовать с рандомными массивами!
В целом конфигурацией более-менее удобно пользоваться. Да, не так, как было бы с полноценным редактором кода, но всё же. В дальнейшем потихоньку будем улучшать, не стесняйтесь предлагать свои идеи. Предоставленные выше задачи показались мне интересными. Да, они были лёгкими, но всё же, весьма интересными. В следующих статьях постараюсь охватить больше задач. В дальнейшем задачи будут потихоньку усложняться, вместе с ними будут и более подробные объяснения! Ну что ж, пока на этом всё, благодарю за внимание. Подключайтесь к решению алгоритмических задач вместе со мной!