這是我在研究leetcode的solution第一個解決算法時,自己做出的理解,並且爲了大家能看懂,做出了詳細的註釋。
此算法算是劍指Offer36的升級版,都使用的歸併算法,但是此處的算法,難度更高,理解起來更加費勁。
/*
* @Param res 保存逆變對數
* @Param index 保存數組下標索引值,排序數組下標值。
* 此算法使用歸併算法,最大差異就在於merge()方法的轉變
*
*
*/
public List<Integer> countSmaller(int[] nums) {
int[] res = new int[nums.length];
int[] index = new int[res.length];
for (int i = 0; i < res.length; i++) {
index[i] = i;
}
mergeSort(nums, index, 0, nums.length-1, res);
List<Integer> list = new LinkedList<>();
for (int i : res) {
list.add(i);
}
return list;
}
private void mergeSort(int[] nums, int[] index, int l, int r, int[] res) {
if (l >= r) {
return;
}
int mid = (l+r)/2;
mergeSort(nums, index, l, mid, res);
mergeSort(nums, index, mid+1, r, res);
merge(nums, index, l, mid, mid+1, r, res);
}
/*
* 將左右兩邊排序好的數組進行逆序對計算,分別從左邊起始處和右邊起始處開始比較,
* 當,左邊索引值大於右邊時,count++,否則 左邊索引值++;
* count值會一直保留,如果右邊數組遍歷到尾部,左邊數組剩下的數的逆序數都會是count;
*
*
*
*/
private void merge(int[] nums, int[] index, int l1, int r1, int l2, int r2, int[] res) {
int start = l1;
int[] tmp = new int[r2-l1+1];
//記錄逆序對數
int count = 0;
//temp數組的下標值
int p = 0;
while (l1 <= r1 || l2 <= r2) {
//左邊數組遍歷結束後,將右邊剩餘的值放到temp數組中,
if (l1 > r1) {
tmp[p++] = index[l2++];
//右邊數組遍歷結束後,將左邊剩餘的值放到temp數組中,
} else if (l2 > r2) {
//l1是原數組索引值,index[l1]是排序好的原數組中索引值。res[index[l1]]對應的原數組索引位置賦逆變數
res[index[l1]] += count;
tmp[p++] = index[l1++];
} else if (nums[index[l1]] > nums[index[l2]]) {
tmp[p++] = index[l2++];
count++;
} else {
//res存放每個數的最大值
res[index[l1]] += count;
tmp[p++] = index[l1++];
}
}
for (int i = 0; i < tmp.length; i++) {
//根據數組值排序,將對應的索引值放到index數組中。
index[start+i] = tmp[i];
}
}