そのアルゴリズムは悪くありません。私の意見では、SO で通常参照されているアルゴリズムよりも優れています。これは、はるかに単純であるためです。ただし、1 つの大きな欠点があります。両方のベクトルに少なくともk
要素が必要です。(問題は、両方とも同じ数の要素 を持っていることを示してn
いますが、それを指定することn ≥ k
はありません。この関数では、ベクトルの大きさを伝えることさえできません。ただし、これは簡単に解決できます。演習として残します。一般に、さまざまなサイズの配列で機能するには、このようなアルゴリズムが必要ですが、実際にそうです; 前提条件を明確にする必要があるだけです.)
floor
andの使用ceil
は適切で具体的ですが、混乱を招く可能性があります。これを最も一般的な方法で見てみましょう。また、引用された解決策は、配列が 1-index であると仮定しているようです (つまりA[1]
、最初の要素であり、ではありませんA[0]
)。ただし、これから書く説明では、より C に似た疑似コードを使用しているため、それがA[0]
最初の要素であると想定しています。k
したがって、要素である結合セット内の要素を見つけるように記述します。最後に、これから説明するソリューションは、提示されたソリューションとは微妙に異なります。これは、最終的な状態で明らかになります。私見、それは少し良いです。(k+1)th
OK、がシーケンス内のx
要素である場合、シーケンス内に より小さい要素k
が正確に存在します。(繰り返し要素がある場合は扱いませんが、大きな違いはありません。注 3 を参照してください。)k
x
それを知っていてA
、B
それぞれに要素があるとしますk
。(これは、それぞれに少なくともk + 1
要素があることを意味します。)よりも小さい負でない整数をk
選択します。と呼びますi
。そして、そうしましょj
うk - i - 1
(そのようにi + j == k - 1
)。[以下の注 1 を参照してください。] 次に、要素A[i]
と を見てくださいB[j]
。A[i]
他のケースではすべての名前を変更する必要があるだけなので、小さいとしましょう。すべての要素が異なると仮定していることを思い出してください。したがって、現時点でわかっていることは次のとおりです。
1)あるi
要素がA
あります< A[i]
2)あるj
要素がB
あります< B[j]
3)A[i] < B[j]
4) (2) と (3) から、次のことがわかります。
j
5) である要素はせいぜいB
ある< A[i]
6) (1) と (5) から、次のことがわかります。
i + j
7)要素はせいぜい一緒にA
あるB
< A[i]
8) しかしi + j
はk - 1
であるため、実際には次のことがわかっています。
9)k
マージされた配列の要素は、より大きくなければなりませんA[i]
(A[i]
最大でも要素 であるためi + j
)。
答えが よりも大きくなければならないことがわかっているのでA[i]
、A[0] から A[i] を破棄できます (実際には、配列ポインターをインクリメントするだけですが、事実上それらを破棄します)。i + 1
ただし、元の問題から要素を破棄しました。したがって、要素の新しいセット (短縮されA
たものとオリジナルのものB
) から、 elementk - (i + 1)
の代わりにelement が必要k
です。
では、前提条件を確認してみましょう。A
と の両方が最初に要素要素をB
持っていると言ったk
ので、両方とも少なくともk + 1
要素を持っています。A
新しい問題では、短縮されたものと元のものB
がそれぞれ少なくともk - i
要素を持っているかどうかを知りたいです。は大きくないB
ため、明らかにそうです。また、から要素を削除しました。元々は少なくとも要素を持っていたので、現在は少なくとも要素を持っています。それで大丈夫です。k - i
k
i + 1
A
k + 1
k - i
最後に、終了条件を確認しましょう。最初に、非負の整数を選択すると言いi
ましj
たi + j == k - 1
。の場合は不可能ですk == 0
が、の場合は可能ですk == 1
。したがって、何か特別なk
ことをする必要があるのは、0 に達したときだけです。その場合、必要なことは returnmin(A[0], B[0])
です。[これは、あなたが見たアルゴリズムよりもはるかに単純な終了条件です。注 2 を参照してください。]
では、ピッキングの良い戦略は何i
ですか? i + 1
いずれかまたは要素を問題から削除することk - i
になりますが、要素の半分にできるだけ近づけたいと考えています。したがって、 を選択する必要がありますi = floor((k - 1) / 2)
。すぐにはわからないかもしれませんが、j = floor(k / 2)
.
A
とのB
要素が少ないケースを解決する部分は省略しています。複雑ではありません。ご自身で考えてみることをお勧めします。
[1] 見ていたアルゴリズムはi + j == k
(偶数の場合) を選択し、または要素のk
いずれかをドロップします。私の選択は(常に)それらの1つを小さくする可能性がありますが、その後ドロップまたは要素になります。したがって、それはわずかに速く収束するはずです。i
j
i + j == k - 1
i + 1
j + 1
i + j == k
[2] (彼らの) 選択と(私の)選択の違いi + j == k - 1
は、終了条件で明らかです。これらの定式化では、 と の両方が正i
でj
なければなりません。どちらかが 0 の場合、0 の要素を削除するリスクがあり、無限再帰ループになるからです。したがって、定式化では、 の可能な最小値k
は 1 ではなく 2 であるため、終了ケースは を処理k == 1
する必要があり、2 つではなく 4 つの要素を比較する必要があります。価値があるのは、「2つのソートされたベクトルから2番目に小さい要素を見つける」の最良の解決策は次のとおりだと思います: min(max(A[0], B[0]), min(A[1], B[1 ]))、これには 3 つの比較が必要です。これによりアルゴリズムが遅くなることはありません。より複雑です。
[3] 要素が繰り返される可能性があるとします。実際、これは何も変わりません。アルゴリズムは引き続き機能します。なんで?のすべての要素A
が実際には実際の値と実際のインデックスのペアであり、同様に のすべての要素でB
あると見なすことができ、ベクトル内の値を比較するときにインデックスをタイ ブレーカーとして使用することができます。A
ベクトル間では、 ifのすべての要素を優先しA[i] ≤ B[j]
ます。それ以外の場合は、 内のすべての要素にB
。これは、実際には実際のコードをまったく変更しません。なぜなら、実際に異なる方法で比較を行う必要がないからです。ただし、証明のすべての不等式が有効になります。