web-dev-qa-db-ja.com

O(1/n)アルゴリズムはありますか?

O(1/n)アルゴリズムはありますか?

または、O(1)より小さいその他のものはありますか?

325
Shalmanese

この質問は、見かけほど愚かではありません。少なくとも理論的には、O(1 /n)のようなものは、 ビッグO表記

これで、簡単にgx)を1 /xに置き換えることができます…上記の定義が一部のfに当てはまることは明らかです。

漸近的な実行時の成長を推定する目的では、これは実行可能性が低くなります。意味のあるアルゴリズムは、入力が増加するにつれて高速化できません。もちろん、これを満たすために任意のアルゴリズムを構築できます。次のもの:

def get_faster(list):
    how_long = (1 / len(list)) * 100000
    sleep(how_long)

明らかに、この関数は、入力サイズが大きくなるにつれて、ハードウェア(数値の精度、sleepが待機できる最小時間、引数の処理時間など)によって強制される少なくとも制限までは時間がかかりません。制限は定数の下限になるため、実際には上記の関数stillにはランタイムO(1)があります。

しかし、実際にはがあり、実際には、入力サイズが大きくなるとランタイムが(少なくとも部分的に)減少する可能性があります。ただし、これらのアルゴリズムはnot以下の実行時動作を示すことに注意してくださいO(1)。それでも、彼らは面白いです。たとえば、 Horspool による非常に単純なテキスト検索アルゴリズムを使用します。ここでは、検索パターンの長さが長くなると、予想される実行時間が短くなります(ただし、haystackの長さが長くなると、実行時間が長くなります)。

303
Konrad Rudolph

はい。

ランタイムO(1/n)を使用するアルゴリズムは、「空の」アルゴリズムとまったく同じです。

アルゴリズムがO(1/n)であるということは、単一の命令で構成されるアルゴリズムよりも少ないステップで漸近的に実行されることを意味します。すべてのn> n0に対して1ステップより少ないステップで実行する場合、それらのnに対してまったく命令がまったくないようにする必要があります。 'if n> n0'のチェックには少なくとも1つの命令が必要なので、すべてのnに対して命令が含まれていてはなりません。

まとめ:O(1/n)である唯一のアルゴリズムは、空のアルゴリズムで、no命令で構成されます。

133
Tobias

それは可能ではありません。 Big-Oの定義は、より大きくない不等式です。

A(n) = O(B(n))
<=>
exists constants C and n0, C > 0, n0 > 0 such that
for all n > n0, A(n) <= C * B(n)

したがって、B(n)は実際には最大値であるため、nが増加するにつれて減少しても推定は変化しません。

24
sharptooth

sharptoothは正しいです。O(1)が最高のパフォーマンスです。ただし、これは高速ソリューションではなく、固定時間ソリューションを意味します。

興味深いバリエーション、そしておそらく実際に提案されているのは、人口が増えるにつれてどの問題が発生するかということですeasier。私は、1を考えることができますが、不自然で、おしゃべりな答えです:

セット内の2人の誕生日が同じですか? nが365を超えると、trueを返します。 365未満の場合、これはO(n ln n)です。問題はゆっくりと容易にならず、n> 365でO(1)になるだけなので、おそらく素晴らしい答えではありません。

23
Adrian

以前の大きなO表記の学習から、1ステップ(変数のチェック、割り当ての実行など)が必要な場合でも、それはO(1)です。

「定数」は関係ないため、O(1)はO(6)と同じであることに注意してください。 O(n)はO(3n)と同じであると言う理由です。

したがって、1ステップさえ必要な場合、それはO(1)です...そして、プログラムには少なくとも1ステップが必要なので、アルゴリズムが実行できる最小値はO(1)です。しない限り、O(0)であると思いますか?まったく何もしない場合、それはO(1)であり、それが最小値です。

(これを行わないことを選択した場合、それはZenまたはTaoの質問になる可能性があります...プログラミングの分野では、O(1)は依然として最小です)。

またはこれはどうですか:

プログラマ:ボス、私はO(1)時間でそれを行う方法を見つけました!
ボス:する必要はありません。今朝破産しました。
プログラマ:ああ、それはO(0)になります。

15

いいえ、これは不可能です。

Nは1/nで無限大になる傾向があるため、最終的に1 /(inf)を達成します。これは事実上0です。

したがって、問題のbig-ohクラスは、nが大きいO(0)になりますが、nが小さいと一定時間に近くなります。これは賢明ではありません。一定の時間よりも速く実行できるのは以下のことだけです。

void nothing() {};

そして、これも議論の余地があります!

コマンドを実行するとすぐに、少なくともO(1)にいるので、いや、O(1/n)の大王クラスを持つことはできません!

8
Ed James

私はよくO(1/n)を使用して、入力が大きくなるにつれて小さくなる確率を説明します。たとえば、log2(n)フリップでフェアコインがテールになる確率はO(1/n)。

7
Dave

関数をまったく実行しないのはどうですか(NOOP)?または固定値を使用します。それはカウントされますか?

7
SpliFF

O(1)は単に「一定の時間」を意味します。

ループ[1]に早期終了を追加すると、(big-O表記法で)O(1)アルゴリズムをO(n)に変換しますが、高速化します。

トリックは一般的に一定時間アルゴリズムが最適であり、線形は指数関数よりも優れていますが、nが少ない場合、実際には指数アルゴリズムが高速になる可能性があります。

1:この例の静的リストの長さを想定

6
LapTop006

私は、量子アルゴリズムは重ね合わせを介して「一度に」複数の計算を行うことができると信じています...

これが役に立つ答えだとは思わない。

5

この質問を読んで会話が何であるかを理解したい人にとって、これは役立つかもしれません:

|    |constant |logarithmic |linear|  N-log-N |quadratic|  cubic  |  exponential  |
|  n |  O(1)   | O(log n)   | O(n) |O(n log n)|  O(n^2) |  O(n^3) |     O(2^n)    |
|  1 |       1 |          1 |     1|         1|        1|       1 |             2 |
|  2 |       1 |          1 |     2|         2|        4|       8 |             4 |
|  4 |       1 |          2 |     4|         8|       16|      64 |            16 |
|  8 |       1 |          3 |     8|        24|       64|     512 |           256 |
| 16 |       1 |          4 |    16|        64|      256|   4,096 |         65536 |
| 32 |       1 |          5 |    32|       160|    1,024|  32,768 | 4,294,967,296 |
| 64 |       1 |          6 |    64|       384|    4,069| 262,144 |   1.8 x 10^19 |
5
Craig O'Connor

多くの人が正しい答えを持っています(いいえ)ここでそれを証明する別の方法があります。関数を得るには、関数を呼び出して、答えを返さなければなりません。これには一定の時間がかかります。残りの処理がより大きな入力に対してより短い時間であったとしても、答えを出力する(これは単一ビットであると仮定できます)には、少なくとも一定の時間がかかります。

3
Brian Postow

解決策が存在する場合は、一定の時間=すぐに準備してアクセスできます。たとえば、並べ替えクエリが逆順であることがわかっている場合は、LIFOデータ構造を使用します。次に、適切なモデル(LIFO)が選択された場合、データは既にソートされています。

2
Larsson

O(1)を下回ることはできませんが、kがNより小さいO(k)は可能です。それらを sublinear time algorithm と呼びました。一部の問題では、サブリニア時間アルゴリズムは特定の問題の近似解しか提供できません。ただし、データセットが大きすぎるか、すべてを計算するには計算コストが高すぎるため、おおよその解決策で十分な場合があります。

2
Hao Wooi Lim

人口が増えるにつれて、どの問題が容易になりますか? 1つの答えは、ダウンロード速度がノード数の逆関数であるbittorrentのようなものです。車をロードするほど速度が低下しますが、ビットトレントのようなファイル共有ネットワークでは、接続するノードが増えます。

2

指摘されているように、null関数の例外の可能性は別として、O(1/n)関数はありません。時間がかかるため、0に近づく必要があります。

もちろん、Konradで定義されているようなアルゴリズムがいくつかありますが、それらは少なくとも何らかの意味でO(1)よりも小さいはずです。

def get_faster(list):
    how_long = 1/len(list)
    sleep(how_long)

これらのアルゴリズムを調査する場合は、独自の漸近的測定値または時間の概念を定義する必要があります。たとえば、上記のアルゴリズムでは、一定の回数の「無料」操作の使用を許可できます。上記のアルゴリズムで、睡眠以外のすべての時間を除外してt 'を定義すると、t' = 1/n、つまりO(1/n)になります。漸近的な振る舞いは取るに足らないものなので、おそらくより良い例があります。実際、そこにいる誰かが重要な結果をもたらす感覚を思いつくことができると確信しています。

1
Casebash

O(1/n)はO(1)より小さくありません。基本的に、データが多いほどアルゴリズムが速くなります。配列を取得し、常に最大10個まで入力するとします。100 それより少ない場合は要素を、それより多い場合は何もしません。これはもちろんO(1/n)ではなく、O(-n)のようなものです:)大きすぎるO-big表記は負の値を許可しません。

1
vava

残りの回答のほとんどは、big-Oがアルゴリズムの実行時間のみに関するものであると解釈します。しかし、質問はそれについて言及していなかったので、数値解析における他のbig-Oのアプリケーションについて言及する価値があると思いました。これはエラーについてです。

多くのアルゴリズムは、ステップサイズ(h)と分割数(n)のどちらを話しているかによって、O(h ^ p)またはO(n ^ {-p})になります。たとえば、 オイラーの方法 では、y(h)およびdy/dx(yの導関数)がわかっている場合、y(0)の推定値を探します。 。 y(h)の推定値は、hが0に近いほど正確です。したがって、任意のxに対してy(x)を見つけるには、0からxまでの間隔を取り、それを分割します。 n個になるまで、各ポイントでオイラーのメソッドを実行して、y(0)からy(x/n)からy(2x/n)のように取得します。

したがって、オイラーの方法はO(h)またはO(1/n)アルゴリズムです。ここで、hは通常、ステップサイズとして解釈され、nは間隔を分割する回数として解釈されます。

浮動小数点の丸め誤差 のため、実際の数値解析アプリケーションでO(1/h)を使用することもできます。間隔を小さくすると、特定のアルゴリズムの実装でキャンセルが発生し、有効数字が失われるため、エラーがアルゴリズムを介して伝播されます。

オイラーの方法では、浮動小数点を使用している場合、十分に小さいステップとキャンセルを使用し、大きな数値に小さな数値を追加して、大きな数値を変更しません。 2つの非常に近い位置で評価された関数から2つの数値を互いに減算して微分を計算するアルゴリズムの場合、y '(x)を(y(x + h)-y(x)/h)で近似します。滑らかな関数では、y(x + h)はy(x)に近くなり、結果として大きな相殺と、有効数字の少ない導関数の推定になります。これは、派生物を必要とするアルゴリズム(境界値の問題など)に伝播します。

1
Andrew Lei

数値解析では、近似アルゴリズムは近似公差に準一定の漸近的複雑さを持たなければなりません。

class Function
{
    public double[] ApproximateSolution(double tolerance)
    {
        // if this isn't sub-constant on the parameter, it's rather useless
    }
}
0
Sam Harwell

OK、私はそれについて少し考えましたが、おそらくこの一般的な形式に従うことができるアルゴリズムが存在します:

1000ノードグラフの巡回セールスマン問題を計算する必要がありますが、訪問できないノードのリストも表示されます。訪問でき​​ないノードのリストが大きくなると、問題の解決が容易になります。

0
Shalmanese

O(1/n)のアルゴリズムが明らかに上限に達していることがわかります。

ルーチンの外部に起因して変化する入力の大規模なシリーズがあり(ハードウェアを反映している場合や、それを実行するプロセッサの他のコアである場合もあります)、ランダムではあるが有効な入力を選択する必要があります。

これで、変更されていない場合は、単にアイテムのリストを作成し、ランダムに1つを選択してO(1)時間を取得します。ただし、データの動的な性質によりリストを作成することはできないため、ランダムにプローブしてプローブの有効性をテストするだけです。 (そして、返されたときに答えがまだ有効であるという保証は本質的にないことに注意してください。これには、たとえば、ゲーム内のユニットのAIなど、用途があります。引き金を引く)

これは、無限大という最悪の場合のパフォーマンスですが、データスペースがいっぱいになると平均的なケースのパフォーマンスは低下します。

0
Loren Pechtel

これはどうですか:

void FindRandomInList(list l)
{
    while(1)
    {
        int Rand = Random.next();
        if (l.contains(Rand))
            return;
    }
}

リストのサイズが大きくなると、予想されるプログラムの実行時間が短くなります。

0
Shalmanese

O(1)未満は不可能だと思います。アルゴがとる時間は、O(1)と呼ばれます。しかし、O(1/n)の場合、以下の関数についてはどうでしょう。 (このソリューションには既に多くのバリアントが存在することはわかっていますが、それらにはすべていくつかの欠陥があると思います(メジャーではなく、コンセプトを十分に説明します)。

def 1_by_n(n, C = 10):   #n could be float. C could be any positive number
  if n <= 0.0:           #If input is actually 0, infinite loop.
    while True:
      sleep(1)           #or pass
    return               #This line is not needed and is unreachable
  delta = 0.0001
  itr = delta
  while delta < C/n:
    itr += delta

したがって、nが増加すると、関数の所要時間はますます短くなります。また、入力が実際に0の場合、関数が戻るまでに時間がかかることが保証されます。

機械の精度によって制限されると主張するかもしれません。したがって、sinc eitにはO(1)の上限があります。しかし、文字列でnとCの入力を取得することで、これをバイパスすることもできます。そして、文字列に対して加算と比較が行われます。アイデアは、これにより、nを任意に小さくできるということです。したがって、n = 0を無視しても、関数の上限は制限されません。

また、実行時間をO(1/n)とだけ言うこともできないと思います。しかし、O(1 + 1/n)のようなものを言う必要があります

0
user1953366