10

これが問題であり、並べ替えられていない配列であり、範囲内の最小数と絶対値a[n]を見つける必要があります。kth[i, j]1<=i<=j<=n, k<=j-i+1

通常、私はquick-findジョブを実行するために使用しますが、範囲が異なるクエリ要求が多数ある場合は十分に高速ではありません。時間[i, j]内にクエリを実行するためのアルゴリズムを理解することはほとんどありませんO(logn)(前処理は許可されています)。

どんなアイデアでも大歓迎です。

PS

問題を分かりやすくしましょう。あらゆる種類の前処理が許可されますが、クエリは O(logn) 時間で実行する必要があります。また、find the など、多くの (2 つ以上の) クエリが存在します1st in range [3,7], or 3rd in range [10,17], or 11th in range [33, 52]

範囲[i、j]とは、ソートされていない元の配列などを意味します。

たとえばa[5] = {3,1,7,5,9}、クエリ1st in range [3,4]52nd in range [1,3]53rd in range [0,2]です7

4

6 に答える 6

7

前処理が許可されていて、時間の複雑さにカウントされない場合は、それを使用してサブリストを作成し、探している要素を効率的に見つけることができます。ほとんどの最適化と同様に、これはスペースを時間と交換します。

前処理のステップは、元のn数字のリストを取得して、いくつかの新しいサブリストを作成することです。

これらのサブリストのそれぞれは、元の要素の一部であり、要素 th から始まり、要素nに拡張されてから並べ替えられます。したがって、元のリストは次のとおりです。m

 {3, 1, 7, 5, 9}

あなたにあげる:

 list[0][0] = {3}
 list[0][1] = {1, 3}
 list[0][2] = {1, 3, 7}
 list[0][3] = {1, 3, 5, 7}
 list[0][4] = {1, 3, 5, 7, 9}

 list[1][0] = {1}
 list[1][1] = {1, 7}
 list[1][2] = {1, 5, 7}
 list[1][3] = {1, 5, 7, 9}

 list[2][0] = {7}
 list[2][1] = {5, 7}
 list[2][2] = {5, 7, 9}

 list[3][0] = {5}
 list[3][1] = {5,9}

 list[4][0] = {9}

これは (時間的または空間的に) 安価な操作ではないため、変更操作 (挿入、削除、変更) を行った後、最初にのみ実行するように、リストに「ダーティ」フラグを維持することをお勧めします。

実際、遅延評価を使用してさらに効率を高めることができます。基本的に、開始時および変更操作を実行するたびに、すべてのサブリストを空のリストに設定します。次に、サブリストにアクセスしようとしてそれが空である場合は常に、そのサブリスト (およびその 1 つだけ) を計算してkから、そこから th 値を取得しようとします。

これにより、サブリストが必要な場合にのみ評価され、不必要な再計算を防ぐためにキャッシュされます。たとえば、3 ~ 6 のサブリストの値を要求しない場合、その値は計算されません。

すべてのサブリストを作成するための疑似コードは、基本的に次のとおりです (for両端を含むループ):

for n = 0 to a.lastindex:
    create array list[n]
    for m = 0 to a.lastindex - n
        create array list[n][m]
        for i = 0 to m:
            list[n][m][i] = a[n+i]
        sort list[n][m]

遅延評価のコードはもう少し複雑なので (少しだけ)、そのための疑似コードは提供しません。

次に、(とは元のインデックス) の範囲内で 4 番目に小さい数を見つけるには、非常に高速な O(1) 操作である を検索するだけkです。ijijlists[i][j-i][k-1]

                +--------------------------+
                |                          |
                |                          v
1st in range [3,4] (values 5,9),   list[3][4-3=1][1-1-0] = 5
2nd in range [1,3] (values 1,7,5), list[1][3-1=2][2-1=1] = 5
3rd in range [0,2] (values 3,1,7), list[0][2-0=2][3-1=2] = 7
|             |                         ^    ^    ^
|             |                         |    |    |
|             +-------------------------+----+    |
|                                                 |
+-------------------------------------------------+

これが実際に動作していることを示す Python コードを次に示します。

orig = [3,1,7,5,9]
print orig

print "====="
list = []
for n in range (len(orig)):
    list.append([])
    for m in range (len(orig) - n):
        list[-1].append([])
        for i in range (m+1):
            list[-1][-1].append(orig[n+i])
        list[-1][-1] = sorted(list[-1][-1])
        print "(%d,%d)=%s"%(n,m,list[-1][-1])

print "====="
# Gives xth smallest in index range y through z inclusive.
x = 1; y = 3; z = 4; print "(%d,%d,%d)=%d"%(x,y,z,list[y][z-y][x-1])
x = 2; y = 1; z = 3; print "(%d,%d,%d)=%d"%(x,y,z,list[y][z-y][x-1])
x = 3; y = 0; z = 2; print "(%d,%d,%d)=%d"%(x,y,z,list[y][z-y][x-1])
print "====="

予想通り、出力は次のとおりです。

[3, 1, 7, 5, 9]
=====
(0,0)=[3]
(0,1)=[1, 3]
(0,2)=[1, 3, 7]
(0,3)=[1, 3, 5, 7]
(0,4)=[1, 3, 5, 7, 9]
(1,0)=[1]
(1,1)=[1, 7]
(1,2)=[1, 5, 7]
(1,3)=[1, 5, 7, 9]
(2,0)=[7]
(2,1)=[5, 7]
(2,2)=[5, 7, 9]
(3,0)=[5]
(3,1)=[5, 9]
(4,0)=[9]
=====
(1,3,4)=5
(2,1,3)=5
(3,0,2)=7
=====
于 2013-03-06T01:31:54.400 に答える
6

現在の解は O( (logn)^2 ) です。O(logn)で実行するように変更できると確信しています。paxdiablo のアルゴリズムに対するこのアルゴリズムの主な利点は、スペース効率です。このアルゴリズムは、O(n^2) スペースではなく、O(nlogn) スペースを必要とします。

まず、長さ m と n の 2 つの並べ替えられた配列から k 番目に小さい要素を見つける複雑さは O(logm + logn) です。長さ a、b、c、d の配列から k 番目に小さい要素を見つける複雑さは O(loga+logb+.....) です。

次に、配列全体をソートして保存します。配列の前半と後半をソートして格納するなど。長さ n のソート済み配列が 1 つ、長さ n/2 のソート済み配列が 2 つ、長さ n/4 のソート済み配列が 4 つなどになります。必要なメモリの合計 = 1*n+2*n/2+4*n/4+8*n/8...= nlogn.

i と j を取得したら、連結すると範囲 [i,j] が得られる部分配列のリストを把握します。logn 個のアレイが存在します。それらの中で k 番目に小さい数を見つけるには、O( (logn)^2) 時間がかかります。

最後の段落の例: 配列のサイズが 8 (0 から 7 までのインデックス) であるとします。次のソート済みリストがあります。

A:0-7、B:0-3、C:4-7、D:0-1、E:2-3、F:4-5、G:6-7。

次に、これらの配列へのポインターを使用してツリーを構築し、すべてのノードに直接の構成要素が含まれるようにします。A がルートになり、B と C がその子になります。

ここで、配列のリストを返す再帰関数を実装します。

def getArrays(node, i, j):
    if i==node.min and j==node.max:
        return [node];

    if i<=node.left.max:
        if j<=node.left.max:
            return [getArrays(node.left, i, j)];  # (i,j) is located within left node
        else:
            return [ getArrays(node.left, i, node.left.max), getArrays(node.right, node.right.min, j) ]; # (i,j) is spread over left and right node 
    else:
        return [getArrays(node.right, i, j)]; # (i,j) is located within right node
于 2013-03-06T03:55:39.727 に答える
3

前処理: [k][r] 要素が最初の r 要素の k 番目に小さい要素である nxn 配列を作成します (便宜上 1 インデックスを付けます)。

次に、特定の範囲 [i,j] と k の値を指定して、次の操作を行います。

  1. 行列の [k][j] スロットで要素を見つけます。これを×とします。
  2. 行列の i-1 列を下に移動し、その中に x 以下の値がいくつあるかを調べます (列 0 を 0 個の小さいエントリとして扱います)。構造上、この列はソートされる (すべての列がソートされる) ため、ログ時間で見つけることができます。この値を s と呼ぶ
  3. 行列の [k+s][j] スロットで要素を見つけます。これがあなたの答えです。

たとえば、与えられた 3 1 7 5 9

  • 3 1 1 1 1
  • × 3 3 3 3
  • XX 7 5 5
  • XXX 7 7
  • XXXX 9

ここで、[2,4] の範囲で 2 番目に小さい値 (ここでも 1 インデックス) を求められた場合、まず [1,4] の範囲で 2 番目に小さい値である 3 を見つけます。次に、列 1 を見て、 3 以下の要素が 1 つあることがわかります。最後に、必要に応じて [3][5] スロットで [1,4] の範囲で 3 番目に小さい要素を見つけます。これは 5 です。

これには n^2 スペースと log(n) ルックアップ時間がかかります。

于 2013-03-06T03:25:21.007 に答える
1

これは前処理を必要としませんが、O(logN). これは単純な iterate&count よりも大幅に高速であり、シーケンスの動的変更をサポートできます。

こんなふうになります。長さnがあるとn=2^xしますx。ルート ノードが を表すセグメント ツリーを構築します[0,n-1]。各ノードについて、それがノード[a,b],を表す場合、それぞれが , を表すb>a2 つの子ノードを持つ[a,(a+b)/2]とし[(a+b)/2+1,b]ます。(つまり、再帰的な 2 除算を行います)。

次に、各ノードで、そのセグメント内の数値に対して個別の二分探索ツリーを維持します。したがって、シーケンスの各変更は、次のO(logN)[on the segement]*O(logN)[on the BST].ようにクエリを実行できます。セグメント内の x のランクQ(a,b,x)とします。明らかに、が効率的に計算できれば、 の二分探索で目的の答えを効率的に計算できます (追加の係数を使用します。[a,b]Q(a,b,x)xO(logE)

Q(a,b,x)次のように計算できます: を構成するセグメントの最小数を見つけます。これは、セグメント ツリー[a,b]で実行できます。セグメントごとに、そのセグメントの二分探索木で 未満の要素数を照会します。これらすべての数値を加算して を取得します。O(logN)xQ(a,b,x)

これはする必要がありますO(logN*logE*logN)。しかし、あなたが求めているものとは正確には違います。

于 2013-03-06T08:58:44.453 に答える
0

O(log n) 時間では、配列のすべての要素を読み取ることはできません。ソートされておらず、他に提供された情報がないため、これは不可能です。

于 2013-03-06T01:27:29.983 に答える
-1

最悪の場合でも平均的な場合でも、O(n) よりも優れた方法はありません。すべての要素を確認する必要があります。

于 2013-03-06T01:28:41.827 に答える