アルゴリズム: ランダム要素の挿入、削除、取得に O(1) 時間 --- ハッシュ テーブル + 動的配列

ここに画像の説明を挿入します


1. トピック:

実装RandomizedSetクラス:

  • RandomizedSet()RandomizedSetオブジェクトを初期化する
  • bool insert(int val)要素がval存在しない場合は、項目をコレクションに挿入して return true、それ以外の場合は return false
  • bool remove(int val)要素がval存在する場合は、コレクションから項目を削除して を返しtrue、存在しない場合は を返しますfalse
  • int getRandom()既存のコレクションからランダムな項目を返します (テスト ケースでは、このメソッドが呼び出されたときに少なくとも 1 つの要素がコレクションに存在することが保証されます)。各要素が返される確率は同じである必要があります。

クラスのすべての関数を実装し、各関数の平均時間計算量を満たす必要がありますO(1)


2.分析機能:

  • 質問要件: ランダム要素の挿入、削除、取得の時間計算量は O(1) です。

  • クエリの走査と取得に関しては、配列の時間計算量は O(1) ですが、挿入と削除では val が存在するかどうかを判断する必要があるため、挿入と削除は O(1) を超えます。

  • ハッシュ テーブルは挿入と削除の操作を O(1) 時間で完了できます

  • つまり: ハッシュ テーブル + 動的配列

可変長配列は、ランダムな要素を取得する操作を O(1) 時間で完了できますが、要素が存在するかどうかを O(1) 時間で判断できないため、挿入と削除の操作は O(1) 時間で完了できません。 。ハッシュ テーブルは挿入と削除の操作を O(1) 時間で完了できますが、添字に基づいて特定の要素を見つけることができないため、ランダムな要素の取得を O(1) 時間で完了できません。ランダムな要素の挿入、削除、取得の時間計算量を満たすためには、可変長配列とハッシュ テーブルを組み合わせる必要があります。要素は可変長配列に格納され、各要素はハッシュ テーブルに格納されます。可変長方式 配列内の添字。

挿入操作では、まず val がハッシュ テーブルにあるかどうかを確認します。すでに存在する場合は false を返し、存在しない場合は val を挿入します。操作は次のとおりです。

可変長配列の最後に val を追加します。val
を追加する前の可変長配列の長さは、val が配置されている添字インデックスであり、val と添字インデックスをハッシュ テーブルに格納します。true を返します

削除する場合は、まずハッシュテーブルにvalが存在するかどうかを判定し、存在しない場合はfalseを返し、存在する場合はvalを削除します。

ハッシュ テーブルから val の添え字インデックスを取得する;
可変長配列の最後の要素 last を添え字インデックスに移動し、last の添え字をハッシュ テーブルのインデックスに更新する; 可変長配列の最後の要素を削除
する要素は、ハッシュ テーブル内の val を削除し、
true を返します。

削除操作の焦点は、可変長配列の最後の要素を削除する要素の添え字に移動し、その後、可変長配列の最後の要素を削除することです。この演算の時間計算量は O(1) で、削除演算後に可変長配列内のすべての要素の添字が連続していることが保証されるため、挿入演算やランダムな要素の取得に便利です。

ランダムな要素を取得する場合、可変長配列内のすべての要素の添字が連続しているため、ランダムに添字を選択し、可変長配列のその添字の要素を返します。


3. コード:

class RandomizedSet {
    
    
    List<Integer> nums;
    Map<Integer, Integer> indices;
    Random random;

    public RandomizedSet() {
    
    
        nums = new ArrayList<Integer>();
        indices = new HashMap<Integer, Integer>();
        random = new Random();
    }

    public boolean insert(int val) {
    
    
        if (indices.containsKey(val)) {
    
    
            return false;
        }
        int index = nums.size();
        nums.add(val);
        indices.put(val, index);
        return true;
    }

    public boolean remove(int val) {
    
    
        if (!indices.containsKey(val)) {
    
    
            return false;
        }
        int index = indices.get(val);
        int last = nums.get(nums.size() - 1);
        nums.set(index, last);
        indices.put(last, index);
        nums.remove(nums.size() - 1);
        indices.remove(val);
        return true;
    }

    public int getRandom() {
    
    
        int randomIndex = random.nextInt(nums.size());
        return nums.get(randomIndex);
    }
}

4. 複雑さの分析:

  • 時間計算量: 初期化とさまざまな操作の時間計算量は O(1) です。

    空間計算量: O(n)、n はセット内の要素の数です。要素を格納する配列とハッシュ テーブルには O(n) スペースが必要です。


5. 概要:

O(1) の平均時間計算量の設計は、ハッシュ テーブルから切り離すことができません。
一般に、挿入、削除、取得は配列を使用して実行できるため、配列を選択するだけで簡単です。
配列 + ハッシュ テーブルなど、トピックに応じて 2 つのデータ構造を組み合わせることができます。




この記事が役に立った場合は、忘れずに Yile に「いいね!」を押してください。ありがとうございます。

おすすめ

転載: blog.csdn.net/weixin_45630258/article/details/133265909