それはあなたが何を意味するかに依存します。質問が単純な配列、つまり一連の連続したメモリ位置に関するものであり、初期化の場合、この「行列」のすべてのメモリ位置に値を入れることを意味する場合、答えはノーであり、O(n * m)よりも優れていることは不可能です。私たちはそれを証明することができます:
アルゴリズムfill(A[n][m], init_val)
が正しい(つまり、のすべてのメモリ位置を埋めるA
)複雑さが(の一部ではないことを意味する)g(n,m)
よりも小さいと仮定すると、十分な大きさの場合、=メモリ位置の数になります。メモリ位置を埋めるには1つの操作が必要なため、アルゴリズムはほとんどの場所を埋めることができます[ハードウェアが組み合わせ操作を提供する場合を除いて、少なくとも別のメモリ位置を「選択」する操作も実行する必要があるため、実際には半分です]。、これはアルゴリズムが正しくないことを意味します。O(n*m)
g(n,m)
Ω(n*m)
n
m
g(n,m) < n*m
fill
g(n,m)
n*m
fill
メモリの場所を埋めるのに一定の時間がかかる場合も同じことが当てはまります。より大きな値をk
選択するだけです。n
m
他のすでに提案されているように、O(n^2)
初期化時間を回避するために他のデータ構造を使用できます。amitの提案では、ある種の遅延評価を使用します。これにより、配列をまったく初期化せず、要素にアクセスするときにのみ初期化できます。
これにより、Ω(n^2)
最初はコストが削減されますが、配列の要素にアクセスするにはより複雑な操作が必要になり、さらに多くのメモリが必要になることに注意してください。
インタビュアーが何を意味するのかは明確ではありません。配列をリンクリストに変換するには時間が必要Ω(L)
です(Lは配列の長さ)。したがって、行列全体をリンクリストに変換するには、Ω(n^2)
時間と実際の初期化が必要になります。再帰を使用してもまったく役に立ちません。そのような再帰がT(n) = 2T(n/2) + O(1)
発生するだけで、漸近的な複雑さのメリットはありません。
原則として、すべてのアルゴリズムは、事前に何らかの形式の知識を持っている場合を除いて、少なくともすべての入力をスキャンする必要があります(たとえば、要素がソートされます)。あなたの場合、スキャンするスペースはΘ(n^2)
であり、したがって、それを埋めたいすべてのアルゴリズムは少なくともである必要がありますΩ(n^2)
。この複雑さよりも小さいものは、何らかの仮定を行うか(たとえば、メモリにデフォルトで初期化値が含まれている-> O(1)
)、または別の問題を解決します(たとえば、遅延配列やその他のデータ構造を使用します)。