いいえ、そうは思いません。バケットに割り当てて O(n) のデータを「並べ替える」ことができるように追加のスペースが必要か、O(n) ではないインプレースで並べ替える必要があります。
もちろん、特定の仮定を立てることができれば、常にトリックがあります。たとえば、N < 64K
整数が 32 ビット幅の場合、カウント配列に必要なスペースを現在の配列の上に多重化できます。
つまり、配列に値を格納するために下位 16 ビットを使用し、インデックスに一致する値のカウントを格納するだけの配列に上位 16 ビットを使用します。
簡単な例を使用してみましょうN == 8
。したがって、配列の長さは 8 要素で、各要素の整数は 8 ビット幅ですが、8 未満です。これは、(最初は) 各要素の上位 4 ビットがゼロであることを意味します。
0 1 2 3 4 5 6 7 <- index
(0)7 (0)6 (0)2 (0)5 (0)3 (0)3 (0)7 (0)7
カウントを上位 4 ビットに格納する O(n) 調整の擬似コードは次のとおりです。
for idx = 0 to N:
array[array[idx] % 16] += 16 // add 1 to top four bits
例として、7 を格納する最初のインデックスを考えてみましょう。したがって、その割り当てステートメントはインデックス 7 に 16 を加算し、7 のカウントを増やします。モジュロ演算子は、既に増加した値が下位 4 ビットのみを使用して配列インデックスを指定することを保証するためのものです。
したがって、配列は最終的に次のようになります。
0 1 2 3 4 5 6 7 <- index
(0)7 (0)6 (1)2 (2)5 (0)3 (1)3 (1)7 (3)7
次に、定数空間に新しい配列があり、使用して値int (array[X] / 16)
の数を取得できX
ます。
しかし、それはかなりよこしまであり、前述のように特定の仮定が必要です。インタビュアーが求めていたのは、そのレベルの悪意かもしれませんし、単に、将来の従業員がコーディングの小林丸をどのように扱っているかを見たいだけかもしれません:-)
カウントを取得したらX
、O(N) のままで、合計が所定の になるペアを見つけるのは簡単なことです。基本的なアプローチは、デカルト積を取得することです。たとえば、再びN
8 であり、合計が 8 になるペアが必要であるとします。上記の多重化された配列の下半分は無視します (カウントのみに関心があるため、次のようになります。
0 1 2 3 4 5 6 7 <- index
(0) (0) (1) (2) (0) (1) (1) (3)
基本的に行うことは、配列を 1 つずつ調べて、合計が 8 になる数値のカウントの積を取得することです。
- 0 の場合は、8 を追加する必要があります (これは存在しません)。
- 1 の場合、7 を追加する必要があります。カウントの積は 0 x 3 であるため、何も得られません。
- 2 の場合、6 を追加する必要があります。カウントの積は 1 x 1 であるため、 が 1 回出現し
(2,6)
ます。
- 3 の場合、5 を追加する必要があります。カウントの積は 2 x 1 であるため、 が 2 回出現し
(3,5)
ます。
- 4の場合はご使用いただけない特殊なケースです。この場合、4 がないので問題ありませんが、1 つある場合、ペアになることはできません。ペアリングしている数字が同じ場合、式は (
m
それらがあると仮定して)1 + 2 + 3 + ... + m-1
です。ちょっとした数学的な冒険で、それはm(m-1)/2
.
それを超えると、左側の値とペアになっていますが、これは既に行っているのでやめます。
だから、あなたが終わったもの
a b c d e f g h <- identifiers
7 6 2 5 3 3 7 7
は:
(2,6) (3,5) (3,5)
(c,b) (e,d) (f,d) <- identifiers
その他の値の合計が 8 になることはありません。
次のプログラムは、この動作を示しています。
#include <stdio.h>
int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 4, 4, 4, 4};
#define SZ (sizeof(arr) / sizeof(*arr))
static void dumpArr (char *desc) {
int i;
printf ("%s:\n Indexes:", desc);
for (i = 0; i < SZ; i++) printf (" %2d", i);
printf ("\n Counts :");
for (i = 0; i < SZ; i++) printf (" %2d", arr[i] / 100);
printf ("\n Values :");
for (i = 0; i < SZ; i++) printf (" %2d", arr[i] % 100);
puts ("\n=====\n");
}
上記のビットはデバッグ用です。バケットの並べ替えを行う実際のコードは次のとおりです。
int main (void) {
int i, j, find, prod;
dumpArr ("Initial");
// Sort array in O(1) - bucket sort.
for (i = 0; i < SZ; i++) {
arr[arr[i] % 100] += 100;
}
そして、ペアリングを行うコードで終了します。
dumpArr ("After bucket sort");
// Now do pairings.
find = 8;
for (i = 0, j = find - i; i <= j; i++, j--) {
if (i == j) {
prod = (arr[i]/100) * (arr[i]/100-1) / 2;
if (prod > 0) {
printf ("(%d,%d) %d time(s)\n", i, j, prod);
}
} else {
if ((j >= 0) && (j < SZ)) {
prod = (arr[i]/100) * (arr[j]/100);
if (prod > 0) {
printf ("(%d,%d) %d time(s)\n", i, j, prod);
}
}
}
}
return 0;
}
出力は次のとおりです。
Initial:
Indexes: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Counts : 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Values : 3 1 4 1 5 9 2 6 5 3 5 8 9 4 4 4 4
=====
After bucket sort:
Indexes: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Counts : 0 2 1 2 5 3 1 0 1 2 0 0 0 0 0 0 0
Values : 3 1 4 1 5 9 2 6 5 3 5 8 9 4 4 4 4
=====
(2,6) 1 time(s)
(3,5) 6 time(s)
(4,4) 10 time(s)
入力数字を調べると、ペアが正しいことがわかります。