1. C++ / Говнокод #15383

    +27

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    81. 81
    82. 82
    83. 83
    84. 84
    85. 85
    86. 86
    87. 87
    88. 88
    89. 89
    90. 90
    91. 91
    92. 92
    93. 93
    94. 94
    95. 95
    96. 96
    97. 97
    98. 98
    99. 99
    #include <iostream>
    #include <iterator>
    #include <algorithm>
    #include <vector>
    #include <utility>
    #include <sstream>
    #include <assert.h>
    using namespace std;
    
    struct PeriodDescription{
    	size_t length, repeat_amount, last_items_amount;
    	/*friend ostream& operator<<(ostream& os, const PeriodDescription& s){
    		os<<" (PeriodDescription){"<<s.length<<", "<<s.repeat_amount<<", "<<s.last_items_amount<<"} ";
    		return os;
    	}*/
    };
    
    /*template<class C>
    string co(C&& c){
    	ostringstream r;
    	r<<" (C) {";
    	copy(c.begin(), c.end(), ostream_iterator<typename C::value_type>(r, ", "));
    	r<<"}; ";
    	return move(r.str());
    }*/
    
    vector<PeriodDescription> find_repeat_sequences_since_begin(const string& sequence){
    	vector<PeriodDescription> result;
    	if(sequence.empty())
    		return result;
    	auto position_at_last_period=sequence.begin();
    	const char first_item = *position_at_last_period;
    	const auto after_last=sequence.end();
    	auto position_at_current_period = position_at_last_period;
    	while(true){
    		position_at_last_period=sequence.begin();
    		position_at_current_period = find(next(position_at_current_period), after_last, first_item);
    		PeriodDescription new_period {size_t(distance(position_at_last_period, position_at_current_period)), 1, 0};
    		while(position_at_current_period!=after_last && *position_at_last_period==*position_at_current_period){
    			++position_at_last_period; ++position_at_current_period;
    			if(++new_period.last_items_amount>=new_period.length){
    				new_period.last_items_amount = 0;
    				++new_period.repeat_amount;
    			}
    		}
    		if(new_period.repeat_amount==1 && new_period.last_items_amount==0)
    			return result;
    		result.push_back(new_period);
    		if(position_at_current_period==after_last)
    			return result;
    	}
    }
    
    vector<size_t> generate_FSM_failJumpIndices(const vector<PeriodDescription>& periodDescriptions, const size_t stringLength){
    	vector<size_t> r(stringLength+1);
    	for(const auto& pd : periodDescriptions){
    		for(size_t periodIndex=1; periodIndex<pd.repeat_amount; ++periodIndex)
    			for(size_t indexAtPeriod=0; indexAtPeriod<pd.length; ++indexAtPeriod)
    				r[(periodIndex*pd.length)+indexAtPeriod]=(periodIndex-1)*pd.length + indexAtPeriod;
    		for(size_t indexAtAfterPeriods=0; indexAtAfterPeriods<pd.last_items_amount; ++indexAtAfterPeriods)
    			r[pd.length*pd.repeat_amount+indexAtAfterPeriods]=pd.length*(pd.repeat_amount-1)+indexAtAfterPeriods;
    	}
    	return r;
    }
    
    vector<size_t> make_FSM_failJumpIndices(const string& sequence){
    	return generate_FSM_failJumpIndices(find_repeat_sequences_since_begin(sequence), sequence.size());
    }
    
    class FSM_for_find_equal_ranges{
    	size_t state;
    	vector<size_t> failJumpIndices;
    	string sequence;
    	string::const_iterator find_next(string::const_iterator checkPosition, const string::const_iterator last){
    		struct atReturn{
    			size_t& state;
    			~atReturn(){state = 0;}
    		}nullify{state};
    		if(checkPosition==last)
    			return last;
    		if(sequence.empty())
    			return next(checkPosition);
    		if(size_t(distance(checkPosition, last))<sequence.size())
    			return last;
    		while(true){
    			if(checkPosition==last)
    				return last;
    			if(*checkPosition==sequence[state])
    				++state;
    			else
    				state=failJumpIndices[state];
    			++checkPosition;
    			if(state>=sequence.size())
    				return prev(checkPosition, sequence.size());
    		}
    	}
    public:
    	template<class T>
    	FSM_for_find_equal_ranges(T&& sequence):

    Очередное собеседование. Пригласили на должность дельфина. Но оп отказался проходить собеседование на дельфи.
    http://ideone.com/zp5CRb

    Запостил: USB, 07 Марта 2014

    Комментарии (53) RSS

    • state(0),
      		failJumpIndices(make_FSM_failJumpIndices(sequence)),
      		sequence(forward<T>(sequence))
      	{}
      	
      	typedef vector<pair<string::const_iterator, string::const_iterator>> result_type;
      	result_type operator()(const string& text){
      		result_type r;
      		auto 
      			current = text.begin(), 
      			last = text.end();
      		while(current!=last)
      		{
      			current = find_next(current, last);
      			if(current==last)
      				break;
      			r.push_back({current, next(current, sequence.size())});
      			++current;
      		}
      		return r;
      	}
      };
      
      size_t position(const string& txt, string::const_iterator pos){
      	return size_t(distance(txt.begin(), pos));
      }
      
      void opositions(ostream& s, const string& txt, pair<string::const_iterator, string::const_iterator> pos){
      	s<<"("<<position(txt, pos.first)<<", "<<position(txt, pos.second)<<")"<<endl;
      }
      
      int main() {
      	auto sequenceForFind = "abcdabcdabcdafgabcdabcdabcdafgmt";
      	auto textWhereSearch = "ko_abcdabcdabcdafgabcdabcdabcdafgmt_ko_abcdabcdabcdafgabcdabcdabcdafgmt";
      	FSM_for_find_equal_ranges fsm(sequenceForFind);
      	auto a = fsm(textWhereSearch);
      	for(const auto& i : a) opositions(cout, textWhereSearch, i);
      	return 0;
      }

      Как можно было такую простую задачу запороть?
      Это поиск подстроки в строке aлгоритмом Кнута–Морриса-Пратта.
      Ответить
      • Функция make_FSM_failJumpIndices на дельфи пишется как:
        fail[1]=0;
        for i=2 to length(substring) do begin
          temp=fail[i-1];
          while temp>0 and substring[temp]/=substring[i-1] do
           temp=fail[temp];
          fail[i]=temp+1;
        end;

        Как можно было упороться, чтобы расписать её на большую часть алгоритма? Что он курил?
        Ответить
        • У автора кода всё понятно. В твоей функции, дельфин, я нифига не понял.
          Ответить
      • дай угадаю
        кто-то заработал геморрой, сидя на лекциях по дискретной математике с толстым томиком кнута, и теперь этот геморрой не дает покоя ни ему, ни кандидатам
        Ответить
        • мне кажется, что это лишп говно сменил акк и постит треш с гейдева под видом собеседований
          Ответить
          • навряд ли задачи чисто "сосбеседовские". На гем деве все больше возле практики.
            Ответить
            • > гем деве
              > возле практики
              сомнительно

              > чисто "сосбеседовские"
              Ну я не знаю, кем нужно быть, чтобы на собесе спрашивать Кнута-Морриса-Пратта. Маразм какой-то.

              >> на дельфи пишется как
              уж больно всё похоже на тред, где засветился тарас
              Ответить
              • > Ну я не знаю, кем нужно быть, чтобы на собесе спрашивать Кнута-Морриса-Пратта. Маразм какой-то.
                +1. Я от алгоритма КМП помню только название ;)

                P.S. Что-то мне кажется, что не на то они кандидатов проверяют, совсем не на то...
                Ответить
                • > Я от алгоритма КМП помню только название ;)

                  Аналогично. Если что, томик Кнута недалеко.
                  Ответить
                • Ну вы чего, там же суть в том чтобы не получить O(M*N) при поиске 'aaaab' в 'aaaaaaaaa', для этого небольшую вспомогательную табличку префикс-сдвигов пилят.

                  PS> емнип в жабе и шарпике даже КМП не осилили.
                  Ответить
                  • уговорил - приду домой, достану томик, разберу.
                    Ответить
                  • Ты всё перепутал. Тут строится конечный автомат.
                    Две таблички сдвигов строятся в Алгоритме Бойера — Мура и поиск осуществляются в обратном порядке.
                    Ответить
                    • >>Ты всё перепутал.
                      Конечно-конечно, всё перепутал. Ведь конечный автомат - это ахо-корасик.
                      Извините, но вы нам не подходите
                      Ответить
                    • >Алгоритме Бойера — Мура
                      Бугага. Копипаст с викижопии детектед.
                      Ответить
                • Кстати на основании сего можно построить атаку, на веб-сервер, зная где в коде выполняется indexOf слать специальные строки. Формировать даже проще чем атака для хеш-коллизий.
                  Потому что криворуких макак, которые пилили стандартную либу тоже на собеседовании вот не спрашивали КМП.
                  Ответить
                  • Хеш-массив строится во многих веб-фреймверках автоматом из параметров, а indexof где можно заэксплуатировать?
                    Ответить
                    • contains и indexOf много где нужен - в парсерах какого-то формата (особенно самописных) наверняка такое можно встретить.

                      Например сделать открывающий тег aaaa[...], а потом ищется закрывающий матчится таким же aaaa[..], но там стоит aaaa[..]b. Ограничений по размеру обычно там нет, потому можно заслать метров 100 и пусть CPU радуется квадратичной сложности.
                      Профит.

                      Тут надо код конкретного софта+реализация indexOf изучать на предмет подобного.
                      Ответить
                      • Конкретно - где можно его заэксплуатировать? До уязвимости хеш-коллизий очень легко добраться.
                        Ответить
                        • >До уязвимости хеш-коллизий очень легко добраться.

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

                          В жаве когда букет хеш-мапы пухнет, он превратится в дерево.
                          Потому сложность worst-case O(log(n))
                          Ответить
                          • Это не худший случай хешмапа. Худший случай - список, это если хеш функция реализована так, что возвращает константу...
                            Ответить
                            • Худший - это когда для равных значений получается разный хеш.
                              Ответить
                              • > когда для равных значений получается разный хеш
                                Это не худший, это пиздец котёнку. Хешмап в таких условиях вообще не может работать.

                                А константный хеш - это все-таки правильный хеш, хоть и производительность падает до плинтуса.
                                Ответить
                              • > это если хеш функция реализована так, что возвращает константу
                                > для равных значений получается разный хеш
                                Вы несете чушь, ибо совершенно потеряли нить обсуждения.

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

                                Сортировки вот тоже O(N*log(N)) в среднем (подавляющее большинство случаев), однако многие из них скатываются в O(N*N) при определенных и маловероятных обстоятельствах.
                                Ответить
                                • Хэш сосёт префиксдерево рулит.
                                  Я знаю что оно жрёт память и много кэшпромахов, из-за которых оно в среднем вдвое тормознее хэша, зато стабильнее.
                                  Ответить
                                  • >Хэш сосёт префиксдерево рулит.
                                    Нет. Я так считал лет 10 назад, когда плохо понимал как работают хеш-мапы.

                                    >из-за которых оно в среднем вдвое тормознее хэша
                                    Нет. "Вдвое" - это полнейший бред.
                                    хеш - O(1). дерево - O(log(N)).


                                    >В жаве когда букет хеш-мапы пухнет, он превратится в дерево.
                                    Как тебе такой гибрид?


                                    >префиксдерево
                                    Оно в теории жрёт памяти меньше, чем любая другая структура, но на практике не оправдывает себя, обычное двоичное дерево его уделает.
                                    Ответить
                                    • > хеш - O(1).
                                      > дерево - O(log(N)).

                                      Очень умно, ага O(длина ключа) когда надо считаем единицей, а когда надо - логарифмом, ага.
                                      Ответить
                                      • N - кол-во элементов в мапе.
                                        Хеш на тяжелых объектах (большие немутабельные строки) обычно кешируется при создании в константу.
                                        Ответить
                                        • Тогда хэш (и вообще ВСЁ) - тоже за логарифм. Потому что чтобы распознать ключ, надо просканировать его полностью, это O(длина ключа), а это O(logN).

                                          А если заранее запомнить типа "вот для строки, хранящейся вот тут - такой-то хеш" - так тогда нафиг хеш, можно просто брать ИД.
                                          Ответить
                                          • Нет. В случае хеша кол-во сравнений ограничено количество элементов в хеш-букете (если адресация не мапы открытая), а там их обычно 1-3 штуки.

                                            В случае дерева (BST), кол-во сравнений O(log(N)), ибо вложенность растёт пропорционально логарифму от числа элементов.

                                            Префиксное же дерево, оно же бор, да O(len(search)), но на практике по производительности полная херня - наверное из-за произвольных выборок памяти, которые трудно предугадать.
                                            Ответить
                                            • > В случае хеша кол-во сравнений ограничено количество элементов в хеш-букете (если адресация не мапы открытая), а там их обычно 1-3 штуки.

                                              А ничё, что каждое сравнение - это O(logN) в хадшем случае?

                                              Я ж говорю, вы удобно устроились, когда надо - вы считаете длину ключа как логарифм, когда надо - не считаете вообще.

                                              > но на практике по производительности полная херня

                                              Если нужна алгоритмическая стабильность - то не херня.
                                              Ответить
                                              • каждое сравнение - это O(len(search_text)
                                                >вы считаете длину ключа как логарифм
                                                То я о BST.

                                                >Если нужна алгоритмическая стабильность - то не херня.
                                                Ну у хеша есть одно полезное свойство когда его сложность минимальна - если элементов в букете вообще нету, тогда сложность будет O(1), хотя в префиксе такое будет если нет слов, начинающихся на.
                                                В противном случае, да ты прав O(len(search_text)
                                                Ответить
                                                • Ты забываешь о генерации хеша, для строки он за O(длина строки)
                                                  Ответить
                                                • У пузырька тоже есть полезное свойство когда его сложность минимальна - это если элементов меньше 10.
                                                  Ответить
                                          • > и много кэшпромахов
                                            А, ну ты об этом уже сказал. Короче у trie идея красивая - безусловно, но в реальном железе оно плохо работает.
                                            Ответить
                                • >Вы несете чушь, ибо совершенно потеряли нить обсуждения.
                                  Всем похуй.
                                  Ответить
                                • И как это противорчит сказаному? Ну и что, что у хеш функции будет константая сложность? хеширование, это в любом случае потеря информации, если так подобрать значения, что хеш функция будет терять именно ту информацию, которой эти значения различались, то мы и получим худший формальный случай хешмапа - O(n).
                                  А вот возвращать разные значения хеш-функция не может по определению - она не будет хеш функцией в таком случае.
                                  Ответить
                          • > а в пыхе который многие обсирают стоит ограничение на размер запроса.
                            Он везде стоит. Каков его размер?

                            Кстати, кто поможет найти сплоит к питону?
                            Ответить
                      • proof of concept давай, так болтовни много.
                        Ответить
              • > чтобы на собесе спрашивать
                Сказывают, что в йандексе вопрошают всякие-разные алгоритмы. КМП - среди них.
                Ответить
                • ирония судьбы, спорить о вопросах на собеседовании в яндексе с человеком, который в нем работает
                  Ответить
                  • Ну, я не спорю, просто систематически перечитывал разные треды на скуеле.ру, там кто-то в теме про вакансии йандекса писал про лютое задротство на алгоритмы и структуры данных. Как-то ненавязчиво вспомнилось.
                    А вот в мылору, из тех же источников, задача про уточку.
                    Ответить
                    • > задача про уточку
                      Что за задача?
                      Ответить
                      • Гуглится по запросу "задача про утку и лису".
                        На всякий случай приведу текст. Источник не оригинальный, но условия неизменны, обычно.
                        „Есть озеро в форме круга. В центре озера находится утка, на краю озера находится лиса. Утка может двигаться по воде со скоростью v, лиса - по окружности озера со скоростью 4v. Утке нужно попасть на берег так, чтобы в этой точке не было лисы.”
                        Общая суть сводится к вопросу: возможно ли уточке попасть на берег, если да, то как.
                        Ответить
                        • Отличная задача. Интересная. Там надо двигаться по какой-то спирали и есть какое-то граничное отношение скоростей, после которого на берег не выйти.
                          А еще хорошая задача про 2(3, 4, ... n) термометров у которых есть предел прочности, и надо измерить максимальную температуру, которую они могут выдержать - от 0 до 1000 градусов, с шагом 10. При этом сделав минимальное число измерений.

                          Полезно для оптимизации поиска в каких-либо структурах, например данные на ленте которую нельзя перемотать назад, а надо делать полный цикл/оборот, то есть где штраф за превышение границы данных очень велик.
                          Ответить
                          • > и есть какое-то граничное отношение скоростей
                            Есть. Кажется, оно около π.
                            Ответить
    • У меня вот такой вопрос, Вы задачу на собеседовании прям так и ставите поиск подстроки алгоритмом Кнута–Морриса-Пратта? Я не хочу обидеть этих двоих (или троих) людей но я до сегодняшнего дня даже не знал что у них есть свой алгоритм поиска (насчет шлюх и тому подобного не уверен).
      Ответить

    Добавить комментарий