O(n)の複雑さで順序付けされた単語の頻度


11

Java開発者のポジションへのインタビュー中に、私は次のことを尋ねられました。

2つのパラメーターを取る関数を記述します。

  1. テキストドキュメントを表すStringおよび
  2. 返すアイテムの数を提供する整数。

最も頻度の高い単語が最初に出現する単語の頻度で並べられた文字列のリストを返すように関数を実装します。ソリューションは時間で実行する必要がありますはドキュメントの文字数です。O(n)n

以下は私が(疑似コードで)答えたものです、それはソートのためにではなく時間です。どうやって回するのかわからない。 O(n)O(nlogn)O(n)

wordFrequencyMap = new HashMap<String, Integer>();
words = inputString.split(' ');

for (String word : words) {
  count = wordFrequencyMap.get(word);
  count = (count == null) ? 1 : ++count;
  wordFrequencyMap.put(word, count);
}

return wordFrequencyMap.sortByValue.keys

誰かが知っているか、誰かが私にいくつかのヒントを与えることができますか?


1
ハッシュテーブルを使用します。
Yuval Filmus 14年

ハッシュテーブルを使用しても問題は解決しません。さらに、ハッシュテーブルはレガシーJavaです。
user2712937 2014年

ハッシュテーブルは通常、複雑さをから下げるための秘訣です。それらがレガシーJavaであっても、それが何であれ意味します。私はこの特定のケースをチェックしていませんので、あなたは正しいかもしれません。O n O(nlogn)O(n)
Yuval Filmus 14年

@YuvalFilmus。おかげで、ハッシュテーブルは、既に使用しているハッシュマップとほとんど同じです(2つのデータ構造の主な違いは同期であり、ここでは適用されません)。私のlog(n)はハッシュマップの値をソートすることから来ています。
user2712937

3
ちなみに、このサイトはコードではなく概念とアルゴリズムに焦点を当てています。したがって、通常はJavaコードを削除して、アプローチの概念的な説明を提供するようお願いします(必要に応じて、簡潔な高レベルの疑似コードを使用することもできます)。また、このサイトで関連する質問は、どのデータ構造とアルゴリズムを使用するかです。特定のJava APIはこのサイトのトピックから外れています(ただし、StackOverflowで質問することもできます)。同様に、HashtableレガシーJava であるかどうかは、このサイトの目的とは無関係です。
DW

回答:


10

分布カウントのバリエーションを提案します。

  1. テキストを読み、出会ったすべての単語をtrieに挿入します。各ノードには、このノードで表される単語が出現した頻度のカウントを維持します。さらに、最高の単語数を追跡しますmaxWordCound。- O(n)
  2. サイズの配列を初期化しますmaxWordCount。エントリタイプは文字列のリストです。- 、カウントが高くなることができないからです。O(n)
  3. トライをトラバースし、ノードごとに、対応する文字列をカウントで示された配列エントリに追加します。- 列の全長がで囲まれているので、NO(n)n
  4. 配列を降順でトラバースし、必要な数の文字列を出力します。- 、それはサイズおよびアレイ内のデータの量の両方に結合されるからです。O(n)

おそらく、最初のフェーズでトライを他のデータ構造に置き換えることができます。


+1、これについてはよくわかりません。返す単語の数は文字数のnによって制限されるため、O(n)ですが、これは質問の質問ですか?または、返された単語の数に依存しない結果ですか?
Nikos M. 2014

@ニコス それはありますは、必要な仮定ではなく、返される単語数の一般的な最悪の上限です。n
ラファエル

@Raphael、正解です。インタビューで質問されたので、これについて考えています。質問で考えられるトリック..
Nikos M.

スペース効率の良い線形時間アルゴリズムがあるかどうか疑問に思っています。
saadtaame 2014年

3
@saadtaame、うん、それは興味深い質問です。別の質問として個別に投稿する価値があるかもしれません。スペース効率だけではありません。トライソリューションもポインタを集中的に使用するため、実際の速度が遅くなる可能性があります(実際のマシンでメモリ階層がどのように機能するかを考えると)。「効率」は最悪の場合の実行時間とは異なります。きれいなのは珍しいことではありません時間アルゴリズムは、ポインタを多用するビートにO N 時間アルゴリズムを、この質問はすでに実際にはより良い選択かもしれないいくつかの潜在的なアルゴリズムを除外しているように見えるので、。O(nlgn)O(n)
DW

3

出現回数の収集はO(n)なので、トリックは実際には上位k件の出現回数のみを見つけることです。

ヒープは上位k値を集計する一般的な方法ですが、他の方法を使用することもできます(https://en.wikipedia.org/wiki/Partial_sortingを参照)。

kが上記の2番目のパラメーターであり、問​​題ステートメントの定数であると想定します(あるように見えます):

  1. 各ノードの出現回数で単語のトライを作成します。
  2. サイズkのヒープを初期化します。
  3. トライをトラバースし、min-probe / top-kヒープの各(リーフ、発生回数)ペアを挿入します。
  4. 上位k個の葉とカウントを出力します(これは、各葉を単語にマップするために親ポインターが必要なため、実際には一種の苦痛です)。

ヒープサイズは定数なので、ヒープ操作はO(1)なので、ステップ3はO(n)です。

ヒープは、トライの構築中に動的に維持することもできます。


2

アルゴリズムは時間内に実行されません。ハッシュテーブルにΘ n )を挿入すると、すでにΩ n 2)の時間がかかります(最悪の場合)。O(nlogn)Θ(n)Ω(n2)


以下は間違っています。とりあえず説明のためにここに置いておきます。

次のアルゴリズムは、最悪の時間(一定サイズのアルファベットΣを想定)、nはテキストの文字数で実行されます。O(n)Σn

  1. 構築接尾辞木で、たとえば、テキストのをUkkonenのアルゴリズム

    構築でこれがまだ行われていない場合は、到達可能なリーフの数をすべての(内部)ノードに追加します。

  2. ルートからツリーをトラバースし、最初の(白い)スペースですべてのブランチを切り取ります。

  3. ツリーをトラバースし、各ノードの子のリストをリーフ数でソートします。

  4. ツリーの収量(左から右に葉)は、すべての単語のリストであり、頻度でソートされています。

ランタイムについて:

  1. ウッコネンのアルゴリズム(拡張形式)は時間実行されます。葉の数を維持することは増加しないΘのアルゴリズムの-COSTを。O(n)Θ
  2. テキスト内に出現するすべての単語の文字ごとに1つのノードをトラバースする必要があります。最大異なる単語と文字のペアがあるため、最大n個のノードにアクセスします。nn
  3. 私たちは、ほとんどの訪問のノード(2 CF)と過ごす時間O | Σ |ログ| Σ |= O 1 あたりのノード。nO(|Σ|log|Σ|)=O(1)
  4. 時間O n )の単純なトラバースにより、収量(もちろんサイズ)を取得できます(2を参照)。O(n)O(n)

ランタイムを別の単語の数でパラメーター化することにより、より正確な境界を取得できます。数が少ない場合、ツリーは2の後に小さくなります。


アルゴリズムが正しくありません(ソートされません)。線形時間が可能であるかどうかはもはやわかりません。
ラファエル

1

ハッシュテーブル(たとえば、HashMap)を使用して、すべての単語とその頻度を収集します。次に、counting sortを使用して、頻度の高い順に単語を並べ替えます。すべての頻度はの範囲の整数であるため、ソートのカウントにはO n 時間かかります。予想される総実行時間はO n )です。これは、(面接担当者が質問から除外されたものについて言及していない限り)すべての実際的な目的にはおそらく十分以上です。これは、最悪の場合の実行時間ではなく、予想される実行時間であることを忘れないでください。1..nO(n)O(n)

これは、O n )の最悪の場合の実行時間ではなく実行時間を想定しているため、教師がアルゴリズムクラスで探している答えではない場合があります。インタビューの質問で追加のポイントを獲得したい場合は、当然のことながら、これは予想される実行時間であることを気軽に言及できますが、O n 最悪の場合の実行時間で置き換えることもできます。より洗練されたデータ構造を持つハッシュテーブル-そして、このような状況でアルゴリズム間でどのように選択するかについて詳しく説明させていただきます。O(n)O(n)O(n)

または、少し安全にプレイしたい場合は、答えを出す前に、まず「予想される実行時間と最悪の場合のO n 実行時間の違いを気にしますか?」と尋ねます。次に、それに応じて回答を調整します。面接担当者が実際にどのように選択するかを尋ねられるように準備してください。(もしそうなら、得点してください!それはあなたが球場から打つことができるはずの質問です。)O(n)O(n)


Θ(n)Ω(n2)

私はインタビュアーのために話すことはできませんが、私は彼らのだらしさを同じことの言い訳として使うのをためらっています。また、このサイトは科学について(あなた自身が上記でコメントしたように)であり、手を振って「もっと早く支払いを受けるには」プログラミングトリックについてではありません。
ラファエル

この理解が明確にされている限り、私はそれで大丈夫です。いくつかの暗黙の「理解」が間違った考えを助長したため、混乱のもとに作られた質問が多すぎます。
ラファエル

0

ハッシュテーブルベースのソリューション

Ω(n2)n

nΩ(n)

O(1)O(n)O(n2)n

ハッシュアルゴリズムは、文字数に対して時間的に線形であると想定されています。

基数ソートベースのソリューション

O(kN)kNnkO(n)

2nnO(n)

英語で最も長い数少ない単語は途方もなく長いですが、適切な数(30以下など)で単語の長さを制限し、それに伴う誤差を許容して単語を切り捨てることができます。


Θ(n)Θ(n)

O(n+n)O(n2)

(3)どのハッシュ関数を選択しても、その特定の関数が劣化する入力を見つけることができます。そして、入力を知った後にハッシュ関数を選択することは通常オプションではありません。(そして、おそらくあなたが扱っていたコメントは、典型的なケースではなく、最悪のケースに関するものだったことを思い出してください。)
FrankW

O(n2)

O(n2)O(1)Ω(1)O(1)O(1)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.