1. Java / Говнокод #13661

    +64

    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
    import java.util.ArrayList;
    
    public class Chapter19 {
    	/* find repeat chars in text (in all words of text)
    	 * print repeat chars
    	 * 
    	 */
    	private String stringArray[] = { "Allocates ae neaw Setringa tehat",
    			"represeants tahe same saequence " };
    			
    	final private String alfabetArray = "abcdefghijklmnopqrstuvwxyz"; 
    	private ArrayList <Character> repeatChars; 
    
    	public void run() {
    		
    		printStringArray();			
    		
    		repeatChars = new ArrayList<Character>();
    		extractRepeatChars();
    		
    		if (!repeatChars.isEmpty()) {
    			printRepeatChars();
    		} else {
    			System.out.println("not repeat ");
    		}
    	}
    	
    	private void printRepeatChars(){
    		System.out.println("");
    		for (char c : repeatChars) {
    			System.out.println(c);
    		}	
    	}
    	
    	private void printStringArray(){
    		System.out.println(" ");
    		for (String s : stringArray) {
    			System.out.println(s);
    		}	
    	}
    	
    	
    	public String [][] parseStringArray() {
    		String wordsArray[][] = new String[stringArray.length][]; 
    		for (int i = 0; i < wordsArray.length; i++) {
    			wordsArray[i] = stringArray[i].split("\n|\t| "); 
    		}
    		
    		return wordsArray;
    	}
    
    	
    	public int findRepeatCharInWordsArray(String [][]wordsArray, char c) {		 													
    		for (int i = 0; i < wordsArray.length; i++) { 										
    			for (int j = 0; j < wordsArray[i].length; j++) { 			
    				if (wordsArray[i][j].indexOf(c) < 0) { 
    					return 0; // zodyje c nerastas
    				}
    			}	
    		}
    
    		return 1;
    	}
    
    
    	public void extractRepeatChars() {
    		String wordsArray[][] = parseStringArray();	
    		for (char c : alfabetArray.toCharArray()) {
    			if (findRepeatCharInWordsArray(wordsArray, c) > 0) {
    				repeatChars.add(c);
    			}
    		}
    	}
    
    } // end

    chapter 19

    Запостил: spivti, 24 Августа 2013

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

    • Суть в студию
      Ответить
      • оно работает, находит повторяющиеся буквы в каждом слове текста.

        Оценить структурность кода и где что подправить можна.
        Ответить
        • Кажется, можно обойтись меньшим количеством кода, мягко говоря.
          Ответить
          • И меньшим количеством оффтоп-постов...
            Ответить
            • Где вы увидели в моем сообщение оффтоп?
              Ответить
              • Не в вашем сообщениe (не стоит благодарностей), а в постах spivti. Парой штук назад он хотел, что бы за него лабу сделали, ну а после радушного принятия с хлебом и солью (местными, разумеется), видимо понял, что КГ - это его личный бложек, в котором все будут восторженно рады простыням кода без изюминок и разъяснения. Ведь и так всё ясно: chapter 19 же! Тот самый знаменитый chapter 19!
                Ответить
        • Подряд идущих, или вообще?
          Ответить
    • import java.util.Scanner;
      import java.util.TreeSet;
      
      public class Main {
          public static void main(String []args) throws Exception{
              Scanner sc = new Scanner(System.in);
              TreeSet<Character> st = new TreeSet<Character>();
              String characters = new String();
              while(sc.hasNextLine()){
                  String[] tmp = sc.nextLine().split(" ");
                  for(int i = 0; i < tmp.length; i++){
                      for(int j = 0; j < tmp[i].length(); j++){
                          if(st.contains(tmp[i].charAt(j)))
                              characters += tmp[i].charAt(j);
                          st.add(tmp[i].charAt(j));
                      }
                  }
              }
              st.clear();
              for(int i = 0; i < characters.length(); i++)
                  st.add(characters.charAt(i));
              for(Character ch : st)
                  System.out.println(ch);
          }
      }

      вот вам для сравнения мой говнокод.
      Ответить
    • Код бредовый, но спать очень хочется
      C#
      class Program
          {
              private static string _inputString =  "Allocates aaa neaw Setringa tehat represeants tahe same saequence" ;
         
      
              static void Main(string[] args)
              {
                 
                  Console.WriteLine(Do(_inputString));
                  Console.ReadKey();
      
              }
      
            static public string Do(string inputString)
            {
                var splitString = inputString.Split(new[]{' '});
                var stringBilder = new StringBuilder();
                foreach (var s in splitString)
                {
                    stringBilder.Append(GetRepeatedLetters(s));
                    stringBilder.Append(" ");
                }
                return stringBilder.ToString();
      
      
            }
      
            private static string GetRepeatedLetters(string s)
            {
                var charArray = new List<char>(s.Length);
                var repeates = new List<char>(s.Length);
                var Sb = new StringBuilder();
                for (var i = 0; i < s.Length; i++)
                {
                    if (!charArray.Contains(s[i])) charArray.Add(s[i]);
                    else if (!repeates.Contains(s[i]))
                    {
                        repeates.Add(s[i]);
                        Sb.Append(s[i]);
                    }
      
                }
                var output = Sb.ToString();
      
                return output == "" ? "<no>" :output;
            } 
          }
      Ответить
    • > public int findRepeatCharInWordsArray
      > return 0
      > return 1
      Тяжелое сишное наследие? :) В java есть boolean.

      Задачу не совсем понял. Если я правильно понимаю код - он выводит буквы, которые есть во всех словах (если хоть в одном слове буквы нет - она не выводится). Так и надо?
      Ответить
      • Лично я писал нахождение повторяющих букв в каждом отдельно взятом слове. Мне так больше нравится
        Ответить
        • А я понял условие так, что надо вывести буквы, которые попадаются в тексте больше одного раза
          Ответить
          • Не, я тоже так думал. Но если код ОП'а верный - то буквы, которые есть в каждом слове.
            Ответить
        • Если искать во всех словах: http://ideone.com/YVEUGB
          import qualified Data.Set as Set
           
          text = "Allocates ae neaw Setringa tehat\nrepreseants tahe same saequence"
           
          allWords = concatMap words . lines
          commonLetters = Set.toList . foldl1 Set.intersection . map Set.fromList . allWords
           
          main = do
              putStrLn text
              putStrLn $ commonLetters text
          Ответить
          • Вывод такой же как ввод - дурите нас, товарищ?
            Ответить
          • На хацкеле выглядит, конечно, красиво. И асимптотика, возможно, лучше. Но я так и не научился считать асимптотику для алгоритмов в хацкеле:)
            Ответить
            • map Set.fromList должен занять O(N * M * log(M)) по идее, где N - количество слов, M - макс. длина слова.
              foldl1 Set.intersection - тупо O(N), т.к. букв всего 26, и каждый интерсект считаем как O(1).
              Set.toList тоже будет O(1), т.к. от количества слов не зависит.

              Ну и в итоге, если я нигде не затупил, будет O(N * M * log(M)).
              Ответить
              • В принципе, это самое быстрое, что можно выжать. Для общего случая. А для |Алфавит| == 26 можно написать линейный алгоритм, используя идею сортировки подсчетом.
                Ответить
                • > используя идею сортировки подсчетом
                  Ну или битмаски, как вариант. or по буквам, and по словам.
                  Ответить
                  • Этот вариант, наверное, самый быстрый, но для |алфавита| > 64 уже не проканает, если я правильно понимаю.
                    Ответить
                    • Ну почему. Можно же массив масок завести. Но вот производительность уже просядет - энды на границах слов будут больше жрать.
                      Ответить
                      • Будет асимптотика N*размер массива масок(сколько масок в массиве). Для больших алфавитов это все же не очень гуд. А сортировка подсчетом будет работать хоть до |алфавита| == 1е6 и более. Имею в виду работать за линейное время.
                        Ответить
                        • Кстати, а как учитывать то, что буквы в слове могут попадаться по нескольку раз. Что-то мне кажется, что это собьет подсчет. Или я неправильно понял идею?
                          Ответить
                          • Завести еще один массив, в котором записывать номер слова по индексу буквы. То есть встречалась ли эта буква в этом конкретном слове. Да, будет 2 огромных массива, но все будет работать очень быстро. Хотя может поднятую вами проблему можно решить и без использования доп. массива.
                            Ответить
                            • Но в конце слова его придется обнулять, а он большой..

                              Ну разве что хранить в нем не булы и не количества, а индексы предыдущих букв, чтобы получился связный список. Тогда сброс будет не дольше чем количество разных букв в слове. И мы выходим на линейную асимптотику.
                              Ответить
                              • Обнулять ничего не нужно. Что нам дает идея сортировки подсчетом? Количество вхождений каждого символа в текст. Нужно, чтобы это количество было равно количеству слов. Но если в отдельном слове какая-то буква входит больше одного раза, нам нельзя увеличивать число вхождений в массиве. Поэтому заведем еще один массив, в котором для каждого индекса(читай символа алфавита) будем хранить, в каком слове он встречался последний раз. Если в текущем (исп. счетчик), то мы просто не инкрементируем вхождение данного символа. Много написал:) Надеюсь, вы поймете.
                                Ответить
                                • А, все понял. Отличная идея ;)
                                  Ответить
                                  • А теперь вопрос знатокам: был бы смысл для больших текстов в том, чтобы посортировать слова от самого короткого к самому длинному? Если да, то при каком соотношении количества слов к длине слов?
                                    Ответить
                                    • Я думаю для больших текстов лучше просканировать первое слово, составить массив, а потом вычеркивать из него те буквы, которые не встречаются в последующих словах. в реальном тексте массив очень быстро опустеет и все сведется к проверке наличия 0-2 символов в слове
                                      Ответить
                                      • в смысле 1-2, при опустощении просто выходит из проверки
                                        Ответить
                                        • Ну а что, если алфавит очень большой и слова очень длинные (например, мы говорим не о словах в натуральных языках, а под словами подразумеваем молекулы белков, где буквами являются аминокислоты).
                                          И мы можем получить ситуацию, когда у нас есть 1000 слов по 1000 букв и одно слово из 3 букв, но оно самое последнее?
                                          Ответить
                                          • > И мы можем получить ситуацию, когда у нас есть 1000 слов по 1000 букв и одно слово из 3 букв, но оно самое последнее?
                                            Ну, видимо, имеется в виду 1000 одинаковых слов, состоящих из 1000 разных букв, чтобы получился наихудший случай?

                                            На построение множеств сортировка не повлияет. На вывод результата - тоже. Остается оценить влияние на интерсекты.

                                            Интерсекты в хаскелевском set'е выполняются за O(m+n), где m и n мощности исходных множеств. Пусть m - мощность аккумулятора, n - число разных букв в текущем слове. На n мы повлиять не можем, т.к. от сортировки слова просто меняются местами. m упадет с 1000 до 3. Т.к. в худшем случае без сортировки m и n были равны, а в лучшем (после сортировки) упали в район нуля, получим ускорение интерсектов где-то в 2 раза. Причем это ускорение в константе, а не в асимптотике: с ростом количества и длины слов оно так и останется в 2 раза.

                                            Итого: выигрыш от сортировки составит <= 0.5 * T(intersection).

                                            P.S. И я совсем не уверен, хотя и могу ошибаться, что сама сортировка не сожрет весь этот профит ;)
                                            Ответить
                                          • Все зависит от постановки задачи. Если оффлайновая, то можно всегда узнать, какое слово наименьшее, хотя бы за 1 проход по массиву. Если онлайн, то придется составлять массив по первому слову.
                                            Онлайн это потоковая.
                                            Ответить
                                          • > И мы можем получить ситуацию, когда у нас есть 1000 слов по 1000 букв и одно слово из 3 букв, но оно самое последнее?
                                            Сложность сортировки у нас зависит от количества слов как N*log(N), а интерсекты - линейно.

                                            Поэтому сделаем такой вывод: при малом количестве слов сортировка может ускорить алгоритм не более чем на 0.5 * T(intersection). При большом количестве слов сортировка увеличит время работы.
                                            Ответить
                                      • > массив очень быстро опустеет
                                        Если уж рассматривать реальный случай - то он почти всегда будет пустым, поэтому if (commonChars.isEmpty()) break ускорит алгоритм еще больше :)
                                        Ответить
                                    • > при каком соотношении
                                      Это вопрос про реализацию, не про алгоритм. Чтобы отвечать на вопросы о сравнении асимптотики недостаточно, надо еще и константы конкретных реализаций оценивать :)

                                      Ну вот что точно скажу - при большом объеме текста сортировка это однозначный фейл. Алгоритм со множествами сам-по себе потоковый, ему памяти надо на текущее множество, на множество-аккумулятор, ну и на I/O буферы. Причем мощность множеств ограничена мощностью алфавита. Если я там с ленивостью нигде не накосячил - хаскелевый код так и будет работать на потоке (а если не будет, то можно попрофайлить и распихать seq, чтобы работал). Алгоритм с сортировкой на потоке работать тупо не сможет.
                                      Ответить
                  • На каждую букву: mask |= 1 << c - 'a';
                    В конце слова: common &= mask;

                    Этот способ по идее самый быстрый и в асимптотике, и на практике ;) Но с вполне понятными ограничениями.
                    Ответить
        • > нахождение повторяющих букв в каждом отдельно взятом слове
          Как-то так? http://ideone.com/uat5H5
          Ответить
    • Вообще подозрительно все это - лабы по работе с текстом на жабе... Никак человек на программиста - журналиста учится
      Ответить
    • (defparameter *lab-2-text*
        "Allocates aaa neaw Setringa tehat represeants tahe same saequence")
      
      (defun common-letters-in-all-words (s)
        (reduce #'intersection
               (mapcar
                (alexandria:compose
                 (alexandria:rcurry #'coerce 'list)
                 #'remove-duplicates)
                (split-sequence:split-sequence #\Space s :remove-empty-subseqs t))))
      
      (common-letters-in-all-words *lab-2-text*)
      ;; (#\a)

      http://rosetta-govnokod.ru
      Ответить
      • > http://rosetta-govnokod.ru
        Не открывается ;( Пойти зарегать что-ли.
        Ответить
    • Если искать буквы, которые есть во всех словах, то вот регесп

      ^\S*(\S)\S*(\s+\S*\1\S*)*\s*$

      Нужная буква в первой группе
      Ответить
      • Надо бы в начале строки тоже пробелы учитывать для симметрии.
        Кстати, возможно ли найти все буквы при условии, что длина слова не ограничена?
        Или, если она ограничена, но длина регекспа не растёт экспоненциально с количеством букв?
        Ответить
        • >Кстати, возможно ли найти все буквы при условии, что длина слова не ограничена?
          так что ли?

          \S*(\S)\S*

          Или без повторений?

          Пример приведите, я что то не понял Вас
          Ответить
          • Вот, как раз был браузер под рукой:
            > a='поезд звездой'
            "поезд звездой"
            > re = /^\S*(\S)\S*(\s+\S*\1\S*)*\s*$/
            /^\S*(\S)\S*(\s+\S*\1\S*)*\s*$/
            > re.exec(a)
            ["поезд звездой", "д", " звездой"]

            А я хочу найти все общие буквы, т.е. о, е, з, д.

            Если поставить условие "длина самого короткого слова - 1 буква", Ваша регулярка находит все общие буквы.
            Если поставить условие с 2 буквами, найдётся строка вида "по полю опали", для которой найдётся только одна буква, а хочется две.
            Можно написать что-то вида /^\s*\S*(\S)\S*(\S)\S*(?:\s+\S*\1\S*\2\S* |\s+\S*\2\S*\1\S*)*\s*$|^\s*\S*(\S)\S*(? :\s+\S*\1\S*)*\s*$/, чтобы иметь 2 буквы.
            В общем случае это будет вида /F(N)|F(N-1)|...|F(1)/, где F(N) = ^\S*, N раз (\S)\S*, (?:\s+G(1)|G(2)|G(3)|...|G(N!)), где G(номер перестановки) = \S*\i1\S*\i2\S*...\iN\S*, а i1...iN - номера 1..N для текущего номера перестановки. Длина этой штуки растёт экспоненциально с ростом регулярного выражения.
            Интересно, можно ли написать "по уму" и избавиться от экспоненты, а также - для бесконечного N.
            Ответить
            • Проще воспользоваться другими средствами - регулярки не заточены под перебор всех вариантов
              можно найти самое короткое слово, растащить его по буквам, а потом собирать регулярку ^\s*\S*(simbol)\S*(\s+\S*simbol\S*)*\s*$ .
              В подавляющем большенстве случаев либо самое маленькое слово будет однобуквенным, или выборка не будет превышать 10.
              Ответить
              • Другими средствами - это да, но во-первых, регулярки обросли синтаксическим сахаром и могут больше, чем когда-то описывали их "матаны", а во-вторых, просто интересно. Для N=∞ скорее всего не прокатит, но может в паре языков запилили расширенные возможности.

                А с участием другого кода (наши возможности тут непомерно возрастают) можно ещё умерить жадность первой \S*: /^\s*\S*?(\S)\S*(\s+\S*\S\S*)*\s*$/ и, "откусывая" первый символ строки до того, как наступит пробел после первого слова, применять регулярку к каждой подстроке.
                Ответить
                • тогда лучше так
                  ^(\S)\S*(\s+\S*\1\S*)*\s*$
                  и применять к обрезаемой строке пока 1 символ не станет пробельным

                  на счет новых веяний - ничего не знаю, я на шарпе прогаю, там старые добрые PCRE без сахара
                  Ответить
    • Нахождение букв, которые есть во всех словах

      C#
      internal class Program
          {
              private const string _inputString = "Allocates neaw Setringa tehat represeants tahe same saequence";
              private static readonly List<char> _chars = new List<char>();
      
              private static void Main(string[] args)
              {
                  Console.WriteLine(Do(_inputString));
                  Console.ReadKey();
              }
      
              public static string Do(string inputString)
              {
                  var splitString = inputString.Split(new[] {' '});
      
                  GetCharsFromWord(splitString[0]);
      
                  var i = 0;
                  while (_chars.Count > 0 && ++i < splitString.Length)
                      RemoveImproperChars(splitString[i]);
      
                  var stringBilder = new StringBuilder();
      
                  foreach (var key in _chars)
                      stringBilder.Append(key);
      
                  return stringBilder.ToString();
              }
      
              private static void GetCharsFromWord(string s)
              {
                    foreach (var ch in s)
                      if (!_chars.Contains(ch)) _chars.Add(ch);
              }
      
              private static void RemoveImproperChars(string s)
              {
                  var i = 0;
                  while (i < _chars.Count)
                  {
                      if (s.Contains(_chars[i]))
                      {
                          i++;
                      }
                      else
                      {
                          _chars.RemoveAt(i);
                      }
                  }
      
              }
          }
      Ответить
    • ну и мой вариант
      void myRun() {
      		Set<String> words = new HashSet<String>();
      		Set<Character> result = new HashSet<Character>();
      		
      		for (String sentence : stringArray) {
      			words.addAll(Arrays.asList(sentence.split("\\s+")));
      		}
      		
      		Iterator<String> wordsIterator = words.iterator();
      		if (wordsIterator.hasNext()) {
      			result.addAll(asCharSet(wordsIterator.next()));
      			while (wordsIterator.hasNext()) {
      				result.retainAll(asCharSet(wordsIterator.next()));
      				if (result.isEmpty()) {
      					break;
      				}
      			}
      		}
      		
      		System.err.println(result);
      	}
      	
      	private Set<Character> asCharSet(String string) {
      		Set<Character> result = new HashSet<Character>();
      		for (char c : string.toCharArray()) {
      			result.add(c);
      		}
      		return result;
      	}
      Ответить
      • Ну собственно логика такая же, как в моем коде на Хаскеле: пересечение множеств символов, составляющих каждое слово. Ну разве что я с каждым словом это делаю, а вы только с различными. Наверное этот код будет побыстрее за счет этого на больших текстах.
        Ответить
    • и как это применимо?
      Ответить
      • Для сдачи лабы это применимо ;)
        Ответить
        • Анально сдал - напился - забылся - ничему не научился

          Схема отработаная годами

          А вообще нужно должное отдать, что человек пытается сдать свою лабу
          Ответить
          • расслабьтесь друзья, я удачно перехожу на питон. Ява не мое. Не подходит она мне.

            Тута мельком прочитал посты борманда, да задание вы поняли правильно. Моя идея заключалась в чем - если есть символ из множества в каждом слове хоть один раз - мы его выводим, ну или в коллекцию пишем. Если он повторяется в том же слове, банально не выводим его.

            Такие задачи тренируют мышление и способствуют набивке руки. Задания брал из Книжки "Ява промышленное программирование".
            Ответить
            • >удачно перехожу на питон

              А ошибки были не на уровне java а на уровне проэктирования. От того, что ты сменишь язык голова по другому работать не начнет.
              Ответить
              • Тоже верно. Жава или си шарп как языки со строгой статической типизацией для начинающих хороши тем, что строже контролирует.
                Ответить
                • Да причем тут языки, если человек не может нормально представить алгоритм выполнения?
                  Ответить
    • Афтар, соизволь приводить текст задания. И да, на питоне это было бы проще сделать (ни в коем случае не агитация за переход)
      Ответить
      • Собственно текст задачки - найти буквы которые повторяются (есть) в каждом слове текста. Их вывести.
        Ответить
        • http://ideone.com/jEtkdf

          Набросал в консоли ipython минут за 5-10.
          Ответить
          • неправильно набросал
            Ответить
          • должны выводиться только а, е .
            Ответить
            • http://ideone.com/OkwofY
              Алгоритм верный, печаталось просто не то, что нужно. К вопросу о жабе и областях видимости.
              Ответить
              • вот мой на питоне

                import string

                text = "The interpreter prients the result oef streing operations"

                def find(text):
                words = text.split()
                repeat_chars = []

                for j in string.letters:
                for i in words:
                key = 1
                if not j in i:
                key = 0
                break

                if key == 1:
                repeat_chars.append(j)

                return repeat_chars


                print find(text)
                Ответить
                • Use [code=python]...[/code], Luke!
                  Ответить
                • любите ли вы квадратичные непотоковые алгоритмы так, как их люблю я
                  Ответить
                  • Ну он не квадратичный, а всего лишь O(m*n), где m - мощность алфавита, n - длина входного текста.

                    А т.к. мощность алфавита константна, считаем что алгоритм имеет сложность O(n).
                    Ответить
                    • Да, что-то я наложал, отсутствие отступов, видимо, подвело. Действительно O(n*m). Но не потоковый.

                      Подумал о том, что для машины N * M и M * N могуть быть совершенно разными вещами: много раз смотреть содержимое небольшого датасета должно быть гораздо выгодее, чем несколько раз просматривать содержимое большого датасета...
                      Ответить
                      • Сейчас в тред придет wvxvw со своим любимым аргументом про алфавит из миллиона символов :)

                        > много раз смотреть содержимое небольшого датасета должно быть гораздо выгодее
                        Чисто из-за работы с внешними устройствами, такими как память. Если бы у проца была одинаковая скорость доступа к любому месту датасета, порядок не имел бы никакого значения :)
                        Ответить
                        • При огромном алфавите и огромной входной строке можно сделать предварительный анализ куска строки, выявить среднюю длину слова и плясать уже от него.
                          На мой взгляд исключать старые варианты лучше чем добалять новые. Берем среднее слово и вычеркиваем буковки

                          А вообще задача бесполезная в такой постановке.
                          Ответить
                          • А как мы узнаем, какие буковки вычеркивать? :) Нука напишите алгоритм :)

                            P.S. Код с пересечением множеств это и есть то самое вычеркивание.
                            Ответить
                            • анализ может показать статистику символов. например в русском языке ф х щ встречаются редко, поэтому приоритетней выбрать слово средней длинны с этими символами - ибо они быстро отсеются.

                              Ответить
                              • выбрать слово средней длинны
                                > И потерять поточность алгоритма.

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

                                Вот и тут, походу, будет та же самая ситуация.

                                > Разность множеств.
                                Можно уточнить, каких?
                                Ответить
                                • Я не предлагаю сортировать.

                                  Например у нас срока в которой первые 100 слов состоят из 1000 букв, а потом идут слова по 5 букв. Нам проще пропустить длинные слова и начать проверять с 1001ого, а потом вернуться и проверить первые. проверять придется не 1000 на 1000 а 5 на 1000. тем более есть шанс, что их вообще проверят не придется (пересечение опустеет)
                                  Ответить
                                  • Это всё эвристики, которые хорошо работают только на специфических входных данных и сливают на других. В общем случае лучше использовать простой, понятный и короткий алгоритм с нормальной ассимптотикой и усложнять только при наличии чётких гипотез относительно входных данных.
                                    Ответить
                                  • > тем более есть шанс, что их вообще проверят не придется (пересечение опустеет)
                                    Вот только на это и надежда :)

                                    > Нам проще пропустить длинные слова
                                    Ну на потоковость алгоритма я так понимаю вам наплевать? :) Эти 100 слов же где-то придется хранить, пока до них дойдет очередь. А если они там все такие... Вот тут-то в игру вступят скорости внешних носителей, и вся ваша оптимизация превратится в тыкву ;)

                                    P.S. А если слова и так читаются с диска - то, имхо, всем насрать на порядок слов, т.к. множества будут строиться и пересекаться гораааздо быстрее, чем слова будут подкачиваться с диска...
                                    Ответить
                                    • я обрезать их не предлагаю. не один ли фиг, откуда начать поиск? завернул в кольцо и идешь по строке
                                      Ответить
                                      • > завернул в кольцо
                                        - "Продавец, заверните мне, пожалуйста, пару сокетов в кольцо".

                                        Хорошо, если эти слова поместились в память, и уже там лежат. А если они, к примеру на диске, или еще хуже вытекают из сокета? Тоже предлагаете 2 раза парсить начальный фрагмент файла? :)

                                        > Например у нас срока в которой первые 100 слов состоят из 1000 букв, а потом идут слова по 5 букв.
                                        А это типичный худший случай. Вон quicksort тоже в худшем случае сливается как говно, затрачивая O(n^2) времени. Но все же прекрасно знают, что худший случай он редкий, и юзают квиксорт.

                                        P.S. Опишите свой алгоритм в каком-нибудь виде (код, псевдокод), чтобы было что обсуждать. Иначе я вот не понимаю, какие множества вы откуда собираетесь вычитать.
                                        Ответить
                                        • не собирался я вычитать.

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

                                          "шла саша по шоссе и сосала сушки"

                                          с "и" выгодней начать

                                          Я не предлагаю кардинально новый алгоритм, я предлагаю немного усовершенствовать старый.
                                          Сорри за невнятные объяснения - засыпаю
                                          Ответить
                                          • > Я не предлагаю кардинально новый алгоритм, я предлагаю немного усовершенствовать старый.
                                            Ок, понял в чем соль.

                                            Ну вот смотрите, попробую попроще объяснить. Алгоритм состоит из двух подзадач - построения множеств и их пересечения. На построение ваша оптимизация никак не влияет. Пересечения ускорятся.

                                            Но построения занимали бОльшую часть времени O(n*log(n)) против O(m+k) у деревянных сетов или даже O(k) для хешсетов... Поэтому эта оптимизация физически не может дать профита более 50%...

                                            Стоит ли ради ускорения не более чем в 2 раза (а скорее всего меньше) терять поточность алгоритма, каждый пусть решает для себя :)

                                            P.S. Если интересно - попробуйте запилить и побенчить исходный и модифицированный алгоритм на примере, который приводили выше (100 слов по 1000, и потом одно короткое), и на средненьком, где слова более-менее разбросаны. Я более чем уверен, что в обоих случаях ускорения более чем в 2 раза не получится. Если получится - снимаю шляпу ;)

                                            P.P.S. Огромное ускорение может получиться только из-за break'а, но давайте все-таки предполагать, что ответ почти всегда не пуст. Иначе кому интересна такая задача, где всегда пустой ответ?
                                            Ответить
                                            • Не понял, о чем вы, но мой алгоритм можно еще улучшить, используя только одно множество.
                                              Ответить
                                            • >Огромное ускорение может получиться только из-за break'а, но давайте все-таки предполагать, что ответ почти всегда не пуст. Иначе кому интересна такая задача, где всегда пустой ответ?

                                              Ну да) Вообще если пологаться на break нужно распараллелить поиск пересечений

                                              Больше чем в 2 раза при наличии общих буковок таки не получится - наоборот замедлится. Увы и ах я полагаюсь на реальные ситуации)

                                              Тут возникает другой вопрос - нафига? У этого алгоритма нет ценности)

                                              P.S. Все сообщения сливаються в один столбец - говнокод такой говнокод

                                              P.S.S. Сегодня по радио задачку передавали для среднего человека
                                              "в доме 7 этажей. на первом живут 2 на втором 4 на третьем 6 и т.д (пирамида перевернутая)
                                              на каком этаже лифт вызывается чаще?"

                                              Ответ всем понятен. А теперь попытайтесь обьяснить без помощи математики)
                                              Ответить
                                              • На первом?
                                                Ответить
                                                • > На первом?

                                                  Но он не сказал, люди ли живут в доме и есть ли там вообще лифт...
                                                  Ответить
                                                  • Сказал, читай внимательно.
                                                    Ответить
                                                  • > Но он не сказал, люди ли живут в доме и есть ли там вообще лифт...
                                                    Лифта нет, но он вызывается? :)

                                                    А вдруг у них 3 этажа под землей, и поэтому лифт чаще всего вызывается на третий?
                                                    Ответить
                              • Повторю доказательство, чтобы не искать его вверху. Любая перестановка слов не влияет на первую фазу, где мы строим множества букв в каждом слове (они просто меняются местами, а от перестановки слагаемых...). Зато она влияет на время пересечений. Но т.к. пересечение сетов выполняется за O(n + m), где m (количество букв в слове) у нас остается неизменным, а n (количество букв в аккумуляторе) мы оптимизнули в район нуля , то мы получаем прирост максимум вдвое.

                                И, при этом, потеряли потоковость алгоритма. Что имхо очень плохой размен.
                                Ответить
                    • Если предположить, что построение множества требует O(log(n) * n), а построение пересечений множеств - O(n), то алгоритм с множествами требует O(log(W)*n), где W - максимальная длина слова, n - кол-во символов. И вот тут W по сути можно считать константой. Т.е. мы не зависим от размера алфавита, и алгоритм полностью линейный и потоковый.
                      На сишке можно написать эффективную реализацию, используя лишь 3 дополнительных массива размера W (проблема только в том, что оно заранее не известо :): ).
                      Ответить
                      • Ну такой алгоритм я уже писал на хаскеле выше. А потом пришел vwxvw со своими алфавитами и словами по миллиону символов и обосрал всю малину ;)

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

                        Еще один потоковый алгоритм выше приводил epic_fail. Там нужно два массива по размеру алфавита. Его алгоритм дает строгое O(n) независимо от размера алфавита (ну еще O(m) на выводе), но вот константа вырастет когда массивы не влезут в кеш.
                        Ответить
                        • Это костыль - юзать массив всех символов.
                          Ответить
                          • Зато это быстрый костыль.
                            Ответить
                            • который жрет память и время программиста на составление алфавита.
                              Ответить
                              • Ну берем юникод. Там всего миллион символов. Берем массив на миллион элементов, он еле-еле но входит в кеш. Профит? :) Тут же никто не заставляет выбирать, какие именно буквы юзаются в данном тексте. Знаем какие - хорошо, можно массивы поменьше сделать. Не знаем - хер с ним, берем худший случай (весь юникод, всю cp1251, всю ascii и т.п.).

                                Производительность будет хуже множеств только на больших алфавитах и коротком тексте.
                                Ответить
                                • Речь может идти о специальном алфавите
                                  Ответить
                                  • > Речь может идти о специальном алфавите
                                    Ну ок, этот способ эффективен для небольших алфавитов (в районе 1000000 символов). Так устроит? :)
                                    Ответить
                              • в питоне алфавит давно есть.
                                Ответить
                                • Да, и , авторы предпологали, наверное, небольшое количество слов в тексте. С практической точки алгоритм корректен и прост.

                                  В теории, на бальших данных - другое дело, юзать другие алгоритмы.
                                  Ответить
                        • Да, как-то я упустил эту ветку, спасибо. Вижу, @kegdan предложил алгоритм с ассимптотикой О(log(W) * n + W * log(W)) в худшем случае (при условии поиска в множестве за O(log(n))) и размером дополнительной памяти W.
                          Ответить
                          • > Вижу, @kegdan предложил алгоритм с ассимптотикой О(log(W) * n + W * log(W)) в худшем случае
                            http://govnokod.ru/13661#comment192861 ?
                            Ответить
                            • Опять затупил, пора домой. Читать код мне было лень, я ориентировался на http://govnokod.ru/13661#comment192889. Ассимптотика хуже. Вариант лучше множеств при условии бесконечного алфавита врядли возможен.
                              Ответить
                • import string
                  
                  text = "The interpreter prients the result oef streing operations"
                  
                  def find(text):
                  words = text.split()
                  repeat_chars = []
                  
                  for j in string.letters:
                  for i in words:
                  key = 1
                  if not j in i:
                  key = 0
                  break
                  
                  if key == 1:
                  repeat_chars.append(j)
                  
                  return repeat_chars
                  print find(text)
                  Ответить
              • Таки да, не то вывел. И таки да, как кто-то сказал, без обьявления переменных нельзя сделать нормальный скоп.
                Ответить
                • > без обьявления переменных нельзя сделать нормальный скоп
                  А в яваскрипте даже с ним не осилили ;)
                  Ответить
                  • Мне больше нравится такой факап:

                    for x in seq:
                        # тратата
                    print x

                    Вылетит с исключением, если seq будет пустым.
                    Ответить
                    • проверить перед итерацией на наличие........

                      из книжек по питону - старайтесь меньше использовать циклы, а больше вшитые функции. так что ваш предыдуший код ок.
                      Ответить
          • То же самое, функциональненько.

            http://ideone.com/3lG30S
            Ответить
            • шикарна, я в восторге. где то тут встречал выражение &= интересно что оно делает ?
              Ответить
              • Не на питоне встречал

                A &= В <==>A = A &B

                обычно это побитовое И
                Ответить
                • В питоне все операции можно перегружать, для множеств это, внезапно, И, только не побитое.
                  Ответить
                  • последнее время я туплю. гребанный недосып
                    Ответить
              • a &= b <=> a = a & b. Очевидно же (ну, для тех, кто знает языки с сишкообразным символом).
                Ответить
    • да, действительно , ваш тоже работает верно, но более хитро сделан.
      Ответить
      • давай, вбрасывай еще задачку - скучно же
        Ответить
        • задачек на java не будет. В принципе можете сами порешать из книжки - java промышленное программирование, авторы Блинов, Романчюк . Я уже упоминал здесь. Скачаете из интернета.
          Только неувлекайтесь сильно.
          Ответить
          • Короче, завязывайте с этим тредом, он уже превратился в кучку сами знаете чего.
            Ответить

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