Сохранен 24
https://2ch.hk/pr/res/2897538.html
Прошлые домены не функционирует! Используйте адрес ARHIVACH.VC.
24 декабря 2023 г. Архивач восстановлен после серьёзной аварии. К сожалению, значительная часть сохранённых изображений и видео была потеряна. Подробности случившегося. Мы призываем всех неравнодушных помочь нам с восстановлением утраченного контента!

Программирование

 Аноним 28/10/23 Суб 13:40:05 #1 №2897538 
Снимок экрана 2023-10-28 в 12.38.24.png
Привет двач. Нужна помощь с одним алгоритмом. Очень хочу оптимизировать ее до O(1).
Пытаюсь конверитровать yyyy mm dd в количество дней от 0000 00 00.

Парочку тестов проходит, но не все. Я использую иной метод, но он имеет сложность O(2n).


Кто-нибудь знает как я могу пофиксить эту дыру и сделать ее O(1) ?
На картинке 2 функции, тот что ниже - сломанный O(1), а выше O(2n)

Высокосный год учитывается!!!
Аноним 28/10/23 Суб 14:30:37 #2 №2897615 
>Пытаюсь конверитровать yyyy mm dd в количество дней от 0000 00
Придумай формулу и запиши кодом
Аноним 28/10/23 Суб 15:39:21 #3 №2897709 
2023-10-28153146.png
2023-10-28153152.png
>>2897538 (OP)
Javaскуф в треде.

У тебя O(n) здесь по двум причинам:
- Константы всегда отбрасываются O(2n) -> O(n)
- У тебя только один цикл из N, второй - константа

Плюс мы не можем считать от 00.00.0000, т.к. по Григорианскому календарю первый год это 1, то же самое по дням. Стартовая дата 01.01.0001

Подразумеваем, что начальная и конечная дата это 00:00 по времени, т.е. если сейчас 02.01.0001, то прошел 1 целый день с момента 01.01.0001

Высокосный год, это год, который либо делится нацело на 400, либо делится нацело на 4 и НЕ делится нацело на 100. Можно записать так: ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)

Чтобы не перечислять все года, можно посчитать, сколько высокосных лет прошло с самого начала исходя из того, что мы знаем выше: (numOfYears / 4) - (numOfYears / 100) + (numOfYears / 400)

Здесь numOfYears это количество прошедших лет. Мы включаем каждый 4-й год, исключаем каждый 100-й год и включаем каждый 400-й год. То есть если текущий год 5, то прошло целых 4 года. Из них 1 будет высокосным.

В конечном итоге мы умножаем кол. высокосных лет на 366, а не высокосных на 365. Далее добавляем количество прошедших дней в зависимости от месяца, текущий день и еще +1 день, если текущий год высокосный и текущий месяц > 2 (после февраля).

https://pastebin.com/0dNF4pqL
Аноним 28/10/23 Суб 15:44:16 #4 №2897717 
2023-10-28154337.png
2023-10-28154348.png
>>2897709
Технически мы можем взять и 0 год, как высокосный, тогда нужно сделать +1 в методе getNumOfLeapYears и numOfYears сделать равным year а не year - 1

https://pastebin.com/T4wyJQz5
Аноним 28/10/23 Суб 15:54:48 #5 №2897730 
Снимок экрана 2023-10-28 в 14.50.23.png
Снимок экрана 2023-10-28 в 14.51.26.png
Снимок экрана 2023-10-28 в 14.53.22.png
>>2897709
Спасибо за отклик. Однако, твой код не проходит эти тесты: [изображение assert-ов]

Я переделал get_day_num так, как это сделал ты, но все ровно не прошло. И кстати, я дополнительно проверяю если yyyy делится на 4000 (если делится - не высокосный год).
Аноним 28/10/23 Суб 16:02:47 #6 №2897734 
>>2897730
> И кстати, я дополнительно проверяю если yyyy делится на 4000 (если делится - не высокосный год).

Ну то есть тесты не проходит не его код, а твой, в котором ты зачем-то посадил баг. Можешь объяснить, зачем ты делаешь эту проверку?

//мимо
Аноним 28/10/23 Суб 16:11:51 #7 №2897752 
>>2897734
Так сказано в одной задаче, которую я пытаюсь решить.

"Правила високосного года по григорианскому календарю:

годы вообще не являются високосными,
за исключением кратных 4, которые являются високосными годами,
за исключением кратных 100, которые не являются високосными годами,
за исключением високосных годов, кратных 400,
за исключением кратных 4000, которые не являются високосными."
Аноним 28/10/23 Суб 16:19:27 #8 №2897764 
>>2897730
А каким образом разница между 01.11.2023 и 30.11.2023 будет 30 дней, если там должно быть 29?

Тоже самое, 01.11.2023 и 01.11.2023 - какого хуя там разница 1, если должно быть 0?

Тесты неверные в общем.
Аноним 28/10/23 Суб 16:22:09 #9 №2897765 
>>2897752
Ну если год кратный 4000, то он априори кратный и 400, поэтому проверка на 4000 лишняя
Аноним 28/10/23 Суб 16:24:37 #10 №2897767 
>>2897765
Не дочитал за "которые не являтся".
Непонятно откуда они взяли (в вики например нет такого, только 4, 100 и 400), но если им так надо, то пусть будет, похуй. В тестах таких кейсов это еще не встречалось.
Аноним 28/10/23 Суб 16:24:47 #11 №2897769 
>>2897752
Пиздец условие понятное конечно
Аноним 28/10/23 Суб 16:41:29 #12 №2897782 
>>2897764
Я сам хз. Такие тесты мне дали. Там надо подсчитать всего количества дней между 2 точками, при этом точки включительны.

То есть в промежутке от 2000 1 1 до 2000 1 30 - 30 дней.
Аноним 28/10/23 Суб 16:46:15 #13 №2897790 
>>2897782
Так ты сам подумай, как вообще возможно пройти следующий тест:

assert(get_day_num(2023,11,1) - get_day_num(2023,11,1) == 1)

Оба результата будут всегда давать одинаковый результат, а значит разница будет всегда 0.
Аноним 28/10/23 Суб 16:47:10 #14 №2897792 
>>2897764
Кстати, я совсем забыл прибавить 1 в каждом assert-е после вычитания разницы между точками; извиняюсь за опечатку.
Аноним 28/10/23 Суб 16:47:15 #15 №2897793 
>>2897782
>при этом точки включительны

Тогда нужно +1 добавлять:
assert(get_day_num(2023,11,1) - get_day_num(2023,11,1) + 1 == 1)
Аноним 28/10/23 Суб 16:49:35 #16 №2897796 
>>2897793
Да-да. Я просто не заметил, как не прибавил 1 к тестам, когда переписывал.
Припишите +1

В общем не все тесты проходят эту проверку
Аноним 28/10/23 Суб 16:56:40 #17 №2897801 
>>2897764
Задание требует найти количество дней в промежутке между точками включительно. Я, когда переписывал тесты для этого треда, забыл прибавить 1 ко всем assert-ам, потому что в сурс файле я это делал в другой функции. То есть тупо забыл прибавить 1, когда переписывал.

Тем не менее, даже если прибавить 1 ко всем assert-ам, то с этими тестами прекрасно справляется тот алгоритм на O(n), а O(1) ломается на некоторых из них.
Аноним 28/10/23 Суб 16:58:59 #18 №2897804 
>>2897801
>а O(1) ломается на некоторых из них.

У меня все прошли, взял первый вариант (от 01.01.0001)
Аноним 28/10/23 Суб 17:07:24 #19 №2897809 
Снимок экрана 2023-10-28 в 16.01.45.png
Снимок экрана 2023-10-28 в 16.02.09.png
Снимок экрана 2023-10-28 в 16.03.04.png
Снимок экрана 2023-10-28 в 16.06.45.png
>>2897804
Я переписал функцию get_day_num так, как мне предложили.

Функция countDays - то, где я присваиваю значения структуры TResult: m_TotalDays и m_WorkDays.

И оно ломается на этом тесте (скрин с assert-ом).
А при попытке вывода значения r.m_TotalDays, оно выводит мне -1967829131

Я еще раз перепроверю детали, которые я упустил
Аноним 28/10/23 Суб 17:14:41 #20 №2897820 
>>2897809
По коду (скринам) логика вроде правильная, попробуй продебажь функцию countDays детальнее
Аноним 28/10/23 Суб 17:23:16 #21 №2897831 
>>2897820
Видимо, когда печатал, я не заметил, как перепутал знак умножения со сложением в функции get_day_num, когда высчитывал int days.

Было:
int days = num_of_non_leap_year 365 num_of_leap_year 366;

Должно было быть:
int days = num_of_non_leap_year
365 + num_of_leap_year * 366;

Ошибка исправлена, все работает прекрасно. Каждому спасибо!
Аноним 28/10/23 Суб 17:33:12 #22 №2897846 
>>2897717
Здесь я кстати ошибся немного, в добавок ко всем правкам нужно еще в методе getNumOfLeapYears() минуснуть numOfYears на 1 перед вычислениями.

Интуиция такая, что если год 4 сейчас, то с нулевого прошло тоже 4, но высокосный должен быть 1 а не 2, потому что года 0, 1, 2, 3, а функция заточена под 0, 1, 2, 3, 4.
Аноним 28/10/23 Суб 17:52:01 #23 №2897886 
Снимок экрана 2023-10-28 в 16.50.17.png
>>2897709
А есть ли возможность узнать количество рабочих дней между двумя точками (включительно) за O(1)?

Судя по условиям, рабочие дни - это дни с понидельника до пятницы. Также мы учитываем доп. выходные (каникулы), а именно: 1-го Января, 1-го Мая, 8-го Мая, 5-го Июля, 6-го Июля, 28-го Сентября, 28-го Октября, 17-го Ноября, 24-го Декабря, 25-го Декабря и 26-го Декабря.

Опять же, мы учитываем высокосный год.

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

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

Можно ли как-то сделать это еще быстрее?
Аноним 28/10/23 Суб 18:09:44 #24 №2897906 
>>2897886
Ну логика здесь примерно та же самая, что и с обычными днями, но чуть посложнее.

Допустим возьмем пример проще для начала - стартовая дата всегда 01.01.0001. Мы точно так же можем посчитать количество выходных - взять количество недель, вычесть из них N выходных дней и т.д. Далее пробить по IFу на каждый особый праздник, типа если текущий день > определенного, то добавляем еще один праздник (как с высокосным годом и февралем в начале было).

Сложность кажется в том, что начало идет не всегда от 01.01.0001. Но здесь все просто вроде. Берешь считаешь количество выходных от 01.01.0001 до стартовой даты. Потом так же считаешь до конечной даты. А потом вычисляешь разницу. Т.е. получаешь промежуток между этими датами.
comments powered by Disqus