33


27

O(1)の挿入、削除、最大

O(1)で挿入/削除/最大操作をサポートしているデータ構造を教えてもらえますか?

7 Answer


56


これは古典的なインタビューの質問であり、通常は次のように表示されます。

_ O(1)時間でプッシュ、ポップ、最小(または最大)操作を行うスタックのようなデータ構造を考案します。 スペースの制約はありません。 _

答えは、メインスタックと最小(または最大)スタックの2つのスタックを使用することです。

たとえば、1,2,3,4,5をスタックにプッシュすると、スタックは次のようになります。

MAIN   MIN
+---+  +---+
| 5 |  | 1 |
| 4 |  | 1 |
| 3 |  | 1 |
| 2 |  | 1 |
| 1 |  | 1 |
+---+  +---+

ただし、5,4,3,2,1をプッシュすると、スタックは次のようになります。

MAIN   MIN
+---+  +---+
| 1 |  | 1 |
| 2 |  | 2 |
| 3 |  | 3 |
| 4 |  | 4 |
| 5 |  | 5 |
+---+  +---+

5,2,4,3,1の場合:

MAIN   MIN
+---+  +---+
| 1 |  | 1 |
| 3 |  | 2 |
| 4 |  | 2 |
| 2 |  | 2 |
| 5 |  | 5 |
+---+  +---+

等々。

アイテムが明確であることがわかっている場合、最小要素が変更されたときにのみ最小スタックにプッシュすることで、スペースを節約することもできます。


14


@KennyTMのコメントは、重要な欠落した詳細を指摘しています-どこに挿入し、どこから削除します。 そのため、スタックのように常に一方の端からのみ挿入と削除を行うと仮定します。

挿入(プッシュ)および削除(ポップ)はO(1)です。

O(1)でMaxを取得するには、追加のスタックを使用して、メインスタックに対応する現在の最大値を記録します。


14


次のソリューションでは、max、push、およびpop操作にO(1)追加メモリとO(1)時間を使用します。 特定の時間に現在の最大要素を追跡する変数maxを保持します。 maxが更新されたときに、スタック内のすべての要素が新しいmax要素よりも小さくなければならないという事実を利用しましょう。 プッシュ操作が発生し、新しい要素(newElement)が現在の最大値よりも大きい場合、スタック内のmax + newElementをプッシュし、max = newElementを更新します。

ポップ操作を行っているときに、現在のポップされた要素が現在の最大値よりも大きい場合、これはmax + elemを保持するためにスタックを更新した場所であることがわかります。 したがって、返される実際の要素はmaxおよびmax = poppedElem-maxです。

例えば。 1、2、3、4、5をプッシュすると、スタックと最大変数は次のようになります。

MAIN       Value of MAX
+---+      +---+
| 9 |      max = | 5 |
| 7 |      max = | 4 |
| 5 |      max = | 3 |
| 3 |      max = | 2 |
| 1 |      max = | 1 |
+---+      +---+

要素をポップするとしましょう。基本的には、max要素(top> maxから)をポップし、max要素を(top-max)に更新します。

MAIN       Value of MAX
+---+      +---+
| 7 |      max = | 4 | = (9-5)
| 5 |      max = | 3 |
| 3 |      max = | 2 |
| 1 |      max = | 1 |
+---+      +---+

ここで、5、4、3、2、1という数字をプッシュするとします。スタックは次のようになります。

MAIN       Value of MAX
+---+      +---+
| 1 |      max = | 5 |
| 2 |      max = | 5 |
| 3 |      max = | 5 |
| 4 |      max = | 5 |
| 5 |      max = | 5 |
+---+      +---+

ポップすると、top <maxであるためスタックのトップがポップされ、maxは変更されません。

以下は、より良い洞察を得るための各操作の擬似コードです。

Elem max;
void Push(Elem x){
    if x < max :
        push(x);
    else{
        push(x+max);
        max = x;
    }
}
Elem Pop(){
    Elem p = pop();
    if |p| < |max|:
        return p;
    else{
        max = p - max;
        return max;
    }
}
Elem Max(){
    return max;
}

プッシュとポップは通常のスタック操作です。 お役に立てれば。


3


比較のみを使用している場合、そのようなデータ構造を見つけるのは難しいでしょう。

たとえば、n個の要素を挿入したり、最大値を取得したり、最大値を削除したり、O(n)時間で数値をソートしたり、理論上の下限をOmega(nlogn)にしたりできます。


0


以下のプログラムは、トップポインターがスタック内の最大値を与えるような方法でスタック内の最大要素を追跡します。したがって、maxはO(1)であり、max [N]によってmaxを見つけることができます。

ITEM   MAX

+---+  +---+
| 1 |  | 1 |
| 10|  | 10|
| 9 |  | 10|
| 19|  | 19| <--top
+---+  +---+

Javaプログラム

public class StackWithMax {

private int[] item;
private int N = 0;
private int[] max;

public StackWithMax(int capacity){
    item = new int[capacity];//generic array creation not allowed
    max = new int[capacity];
}

public void push(int item){
    this.item[N++] = item;
    if(max[N-1] > item) {
        max[N] = max[N-1];
    } else {
        max[N] = item;
    }
}

public void pop() {
    this.item[N] = 0;
    this.max[N] = 0;
    N--;
}

public int findMax(){
    return this.max[N];
}
public static void main(String[] args) {
    StackWithMax max = new StackWithMax(10);
    max.push(1);
    max.push(10);
    max.push(9);
    max.push(19);
    System.out.println(max.findMax());
    max.pop();
    System.out.println(max.findMax());


}

}


0


すでに指摘したように、質問には情報が不足しています。 挿入/削除することも、処理するデータの性質も指定しません。

役に立つ可能性のあるアイデア:あなたは言う、

_ O(1)での挿入/削除/最大操作 _

O(1)でmaximunを挿入、削除、検索できる場合は、n(n)個の要素を挿入してからmax / deleteを取得できるため、このヒポティック手法を使用してO(n)でソートできることに注意してください。それらはすべてソートされます。 比較に基づくソートアルゴリズムはO(nlogn)未満でソートできないことが証明されているため、比較に基づくアプローチは機能しないことがわかっています。 実際、これを行う最速の方法の1つはBrodalキューですが、削除時間はO(1)を超えています。

たぶん、ソリューションは基数ツリーのようなものです。これらすべての操作の複雑さは、キーの量ではなくキーの長さに関係しています。 これは、他の数値でキーの長さを制限できる場合にのみ有効であるため、一定と見なすことができます。

しかし、多分それはそれほど一般的なものではありませんでした。 別の解釈では、挿入/削除は古典的なスタックのものです。 その制限されたケースでは、https://stackoverflow.com/a/3435998/301444 [Can BerkGüder]から提供されたダブルスタックソリューションを使用できます。


-1


ハッシュテーブルは、O(1)での挿入/削除をサポートする可能性がありますが、最大値に関する手掛かりはありません。 おそらく自分で何らかの形で追跡する必要があるでしょう。