Самый эффективный способ найти вершину K частыми словами в последовательности хвастовства

Что такое NullPointerException?

Хорошим местом для начала является JavaDocs . Они охватывают это:

Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:

  • Вызов метода экземпляра нулевого объекта.
  • Доступ или изменение поля нулевого объекта.
  • Выполнение длины null, как если бы это был массив.
  • Доступ или изменение слотов с нулевым значением, как если бы это был массив.
  • Бросать нуль, как если бы это было значение Throwable.

Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.

blockquote>

Также, если вы попытаетесь использовать нулевую ссылку с synchronized, который также выдаст это исключение, за JLS :

SynchronizedStatement:
    synchronized ( Expression ) Block
  • В противном случае, если значение выражения равно null, NullPointerException.
blockquote>

Как это исправить?

Итак, у вас есть NullPointerException. Как вы это исправите? Возьмем простой пример, который выдает NullPointerException:

public class Printer {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer();
        printer.print();
    }
}

Идентифицирует нулевые значения

. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:

Exception in thread "main" java.lang.NullPointerException
    at Printer.printString(Printer.java:13)
    at Printer.print(Printer.java:9)
    at Printer.main(Printer.java:19)

Здесь мы видим, что исключение выбрано в строке 13 (в методе printString). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, что s имеет значение null, а вызов метода length на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когда s.length() удаляется из метода.

Трассировка, где эти значения взяты из

Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что s передается с printString(name) в методе print(), а this.name - null.

Трассировка, где эти значения должны быть установлены

Где установлен this.name? В методе setName(String). С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. ​​

Этого достаточно, чтобы дать нам решение: добавить вызов printer.setName() перед вызовом printer.print().

Другие исправления

Переменная может иметь значение по умолчанию setName может помешать ему установить значение null):

private String name = "";

Либо метод print, либо printString может проверить значение null например:

printString((name == null) ? "" : name);

Или вы можете создать класс, чтобы name всегда имел ненулевое значение :

public class Printer {
    private final String name;

    public Printer(String name) {
        this.name = Objects.requireNonNull(name);
    }

    public void print() {
        printString(name);
    }

    private void printString(String s) {
        System.out.println(s + " (" + s.length() + ")");
    }

    public static void main(String[] args) {
        Printer printer = new Printer("123");
        printer.print();
    }
}

См. также:

Я все еще не могу найти проблему

Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).

80
задан Deduplicator 15 March 2015 в 13:45
поделиться

6 ответов

Предположим, что мы перебрасываемся парой слов "реклама" "рекламы" последовательности "мальчик", "большие" "плохие" "com" "прибывают" "холод". И K=2. когда Вы упомянули, "что делили использование первой буквы слов", мы добрались ("реклама", "реклама") ("мальчик", "крупный", "плохо") ("com" "прибывают" "холод"), "тогда разделение самого большого набора многословного с помощью следующего символа, пока у Вас нет k наборов однословных". это разделит ("мальчик", "крупный", "плохо") ("com" "прибывают" "холод"), первый раздел ("реклама", "реклама") пропущен, в то время как "реклама" является на самом деле самым частым словом.

, Возможно, я неправильно понимаю Вашу точку. Можно ли детализировать процесс о разделе?

0
ответ дан Morgan Cheng 24 November 2019 в 09:59
поделиться

У Вас есть ошибка в Вашем описании: Подсчет берет O (n) время, но сортировка берет O (m*lg (m)), где m является количеством уникальный слова. Это обычно намного меньше, чем общее количество слов, так вероятно, должен просто оптимизировать, как хеш создается.

2
ответ дан martinus 24 November 2019 в 09:59
поделиться

Можно сократить время далее путем разделения использования первой буквы слов, затем деля самый большой набор многословный с помощью следующего символа, пока у Вас нет k наборов однословных. Вы использовали бы sortof дерево с 256 путями со списками частичных/завершенных слов в листах. Необходимо было бы очень стараться не вызвать строковые копии везде.

Этот алгоритм является O (m), где m является количеством символов. Это избегает, что зависимость от k, который очень хорош для большого k [по тому, как Ваше отправленное время выполнения является неправильным, это должен быть O (n*lg (k)), и я не уверен, что это с точки зрения m].

при выполнении обоих алгоритмов рядом Вы получите то, что я вполне уверен, асимптотически оптимальный O (минута (m, n*lg (k))) алгоритм, но мой должен быть быстрее в среднем, потому что это не включает хеширование или сортировку.

2
ответ дан 24 November 2019 в 09:59
поделиться

Если Ваш "список хвастовства" является достаточно большим, можно просто выбрать и получить оценки. Иначе мне нравится агрегирование хеша.

Редактирование :

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

Этот подход действительно только разумен, если у Вас есть так много данных, что обработка всего этого просто довольно глупа. Если у Вас только есть несколько megs, необходимо быть в состоянии пройти через данные и вычислить точный ответ, не потея вместо того, чтобы потрудиться вычислять оценку.

8
ответ дан Aaron Maenpaa 24 November 2019 в 09:59
поделиться

Маленькое изменение на Вашем решении уступает O (n) алгоритм, если мы не заботимся о рейтинге вершины K, и O (n+k*lg (k)) решение, если мы делаем. Я полагаю, что обе из этих границ оптимальны в постоянном множителе.

оптимизация здесь происходит снова после того, как мы пробежим список, вставляя в хэш-таблицу. Мы можем использовать медиана медиан алгоритм для выбора Kth самый большой элемент в списке. Этот алгоритм доказуемо O (n).

После выбора Kth самый маленький элемент, мы делим список вокруг того элемента так же, как в quicksort. Это, очевидно, также O (n). Что-либо на "покинутой" стороне центра находится в нашей группе элементов K, таким образом, мы сделаны (мы можем просто выбросить все остальное, поскольку мы продвигаемся).

, Таким образом, эта стратегия:

  1. Проходят каждое слово и вставляют его в хэш-таблицу: O (n)
  2. Выбор Kth самый маленький элемент: O (n)
  3. Раздел вокруг того элемента: O (n)

, Если Вы хотите оценить элементы K, просто отсортируйте их с любым эффективным видом сравнения в O (k * LG (k)) время, приведя к общему времени выполнения O (n+k * LG (k)).

O (n) с указанием срока оптимален в постоянном множителе, потому что мы должны исследовать каждое слово, по крайней мере, однажды.

O (n + k * LG (k)) с указанием срока также оптимален, потому что нет никакого основанного на сравнении способа отсортировать k элементы в меньше, чем k * LG (k) время.

13
ответ дан 24 November 2019 в 09:59
поделиться

Вы не собираетесь получать обычно лучшее время выполнения, чем решение, которое Вы описали. Необходимо сделать, по крайней мере, O (n) работа для оценки всех слов, и затем O (k) дополнительная работа для нахождения вершины k условиями.

, Если Ваш проблемный набор действительно большой, можно использовать распределенное решение те, которые отображают/уменьшают. Имейте рабочих карты n, считают частоты на 1/энный из текста каждым, и для каждого слова, отправляют его одному из m рабочих редуктора, вычисленных на основе хеша слова. Редукторы тогда суммируют количества. Сортировка слиянием по выводам редукторов даст Вам самые популярные слова в порядке популярности.

22
ответ дан Nick Johnson 24 November 2019 в 09:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: