少額問題
- 簡単な説明
配列があり、左から右にトラバースし、ビットに移動するたびに、それよりも小さいすべての数字を左に追加し、最終的な合計を小計として記録します。以下は、一般的な実践プロセスの例です。
したがって、私たちが必要としているのは、より迅速なアプローチです。
- 分析ロジック
以前のマージソートを引き続き使用して、マージ部分を変更できます。
以下を例に取りますが、それでも配列を 2 つに分割します
図1
図2
それでも2つの指標を準備し、空のリストが役立ちます
左側の 1 を見て、3 の左側の p1 が 1 を指し、右側の p2 が 3 を指す、比較、1<3、小計に 1 を追加、ヘルプ リストに 1 を格納、インジケータ p1 を右に移動範囲外 (左側に数字がない) を選択し、右側の 3 を直接コピーします。ヘルプ リストを入力し、ヘルプ リストを配列にコピーします。(ヘルプ[1,3])
上位層に入り、p1 は 1 を指し、p2 は 2 を指し、1<2、小和に 1 を加算、ヘルプ リストに 1 を格納、p1 は 3 を指し、3>2、小和に 0 を加算、格納2 ヘルプ リストの右側に数字がありません。左側の残りを直接ヘルプ リストにコピーします (help[1, 2, 3])。
(5、6は同じ)
上層に入り、この時点で左右がソートされ、p1が1を指し、p2が5を指し、5>1、(右側も順番なので、5以降の数字はすべて1より大きい) 、次に直接進みます 下付き文字を計算するだけです) 1*2 を小さな和に追加し、ヘルプ リストに 1 を格納します。など、そして最後に配列全体に順序があり、配列の最小合計を見つけます。
(ps: 1. 左側の数値が右側の数値よりも大きい場合、右側の数値をヘルプ リストに保存すると、p2 インジケーターが 1 ビット右に移動します。つまり、小さい方が移動します。ヘルプに入ります; 2. 合計が計算されるたびにソートされるため、ソートは結果に影響しません)
- コード (Java):
public static int process(int[] arr,int L,int R){
if(L==R){
return;
}
int M = L+((R-L)>>1);
merge(arr,L,M,R);
return process(arr,L,M)+process(arr,M+1,R)+merge(arr, L,M,R);
}
public static int merge(int[] arr,int L,int R){
int p1 = L;
int p2 = M+1;
int[] help = new int[R-L+1];
int res =0; //小和
int i = 0;
while(p1 <= M && p2 <= R){
res += arr[p1] < arr[p2] ? (R - p2+1)*arr[p1]:0; //左边小则该数乘右边下标数记小和
help[i] = arr[p1] < arr[p2] ? arr[p1++]:arr[p2++];
while(p1 <= M){
help[i++] = arr[p1++];
}
while(p2 <= R){
help[i++] = arr[p2++];
}
for(int i = 0,i < help.length,i++){
arr[L+i] = help[i]; //把排好序的help拷贝到该次求小和数组范围
return res;
}
}
}
逆ペア問題
- 簡単な説明
配列, 左の数が右の数よりも大きい場合, 逆順のペアとして記録されます. その本質は前の小和問題と同じです. また、マージを変更するだけで済みます. (小さな和を見つけることは、左辺が右辺よりも小さいことを見つけることです)
上記は、配列内のすべての逆のペアです。