アルゴリズム-順序付けられていない配列の中央値の問題を再検討します
アルゴリズム-順序付けられていない配列の中央値の問題を再検討します
順序付けられていない配列が与えられた場合、順序付けられていない配列の中央値を見つけます
この質問は、私が以前に書いたブログのアルゴリズム-TopK関連の問題に言及しました。ヒープまたは高速選択アルゴリズムを使用して実装できます。高速選択アルゴリズムを使用する場合、2つの状況で説明します。1つは配列要素の数が奇数の場合、中央の要素を直接選択できる場合、もう1つは数が偶数の場合、2つのクイック選択を行う場合です。
ただし、上記の方法では、配列要素の数が偶数の場合、最初のクイック選択がアレイに与える影響に注意を払わないため、2番目のクイック選択の時間の複雑さがO(N ^ 2)に達する可能性があります。
実際、高速選択の性質を使用して、2番目の選択の時間の複雑さをO(k-1)に減らすことができます。
クイック選択の原則は、ピボット要素を位置k-1に調整することです。最後に、ピボット要素の左側の要素がピボット要素以上で、右側の要素がピボット要素以下であるか、またはその逆です。
実際、k番目に大きい要素を選択すると、k-1個の最大の要素がピボット要素の左半分または右半分にあると判断できます。
例としてK番目に大きい要素を選択するために、降順で配列を選択します。
1.配列の長さが偶数の場合、nums.length / 2 + 1が最大の要素(m1と表記)とnums.length / 2が最大の要素(m2と表記)を選択する必要があります。m1を選択した後、m2がk-1の左半分にあると判断できます。左半分はすべてm1より大きいため、問題は間隔[0、k-1)の最小値を見つけることです。 m2の場合、間隔の要素を直接トラバースして、最小のm2を見つけることができます。最終結果は(m1 + m2)/ 2です。
2.配列の長さが奇数の場合、nums.length / 2 + 1が最大の要素(m1と表記)を直接選択します。m1は探している中央値です。
このようにして、より高速で単純なコードを取得できます。
@Test
public void test(){
int[] nums={
7,5,9,3,11,32,27,1,-9,4};
//-9,1,3,4,5,7,9,11,27,32
System.out.println(mediumNUmberOfMixArray(nums));
}
public int mediumNUmberOfMixArray(int[] nums){
int k=nums.length/2+1;
quickSelect(nums,0,nums.length-1,k);
int m1=nums[k-1];
if(nums.length%2==1){
return m1;
}else {
int m2=Integer.MAX_VALUE;
for (int i=0;i<k-1;i++){
m2=Math.min(m2,nums[i]);
}
return (m1+m2)/2;
}
}
public void quickSelect(int[] nums,int left,int right,int k){
if(left<right){
int i=left,j=right;
int pivot=nums[left];
while (i<j){
while (i<j&&nums[j]<=pivot){
j--;
}
while (i<j&&nums[i]>=pivot){
i++;
}
if(i<j){
swap(nums,i,j);
}
}
swap(nums,i,left);//恢复枢纽元
if(i>=k){
quickSelect(nums,left,i-1,k);
}else {
quickSelect(nums,i+1,right,k);
}
}
}
private void swap(int[] nums, int i, int j) {
int temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
}