Algorithm practice reverse pair

Algorithm practice reverse pair

The reverse order is very classic for the problem. The simplest brute force attack has a time complexity of O(n 2 ), and the algorithm with a time complexity greater than O(n 2 ) is very bad, so we use the merge sort algorithm to change it. Obtain O(nlogn) algorithm.

Definition of reverse order pair: if i <j && arr[i]> arr[j] in the sequence, then arr[i] and arr[j] are a pair of reverse order pairs.

  • java algorithm reference
// 逆序对个数
private static long ropCount = 0;

/**
 * 计算逆序对
 * 
 * @param arr
 * @param left
 * @param right
 */
public static void calcRop(int[] arr, int left, int right) {
    
    
	if (left >= right)
		return;
	int mid = (left + right) >>> 1;
	calcRop(arr, left, mid);
	calcRop(arr, mid + 1, right);
	calc(arr, left, mid, right);
}

/**
 * 一次计算
 * 
 * @param arr
 * @param left
 * @param mid
 * @param right
 */
public static void calc(int[] arr, int left, int mid, int right) {
    
    
	int i = left;
	int j = mid + 1;
	while (i < j && j <= right) {
    
    
		while (i < j && arr[i] <= arr[j])
			i++;
		ropCount += j - i;
		int temp = arr[j];
		System.arraycopy(arr, i, arr, i + 1, j - i);
		arr[i] = temp;
		i++;
		j++;
	}
}
  • Algorithm test

The correctness test
has so few sets of data

data Number of reverse pairs
{ 9, 8, 7, 5, 2, 4, 5, 6 } 20
{ 7, 5, 5, 4, 3, 3, 5, 4, 4, 1, 6 } 32
{ 9, 8, 7, 1, 2, 3, 4, 3, 2, 1 } 33
{ 7, 5 } 1
{ 5, 5 } 0
{ 5 } 0
{ } 0

After running separately, the results were all correct, and no data was found that did not match the results.
Stress test
Run one million pieces of data to see how long it takes.

int[] arr = new int[1000*1000];
for (int i = 0; i < arr.length; i++) {
    
    
	arr[i] = (int)(Math.random()*100 + 1);
}
long start = System.currentTimeMillis();
calcRop(arr, 0, arr.length - 1);
System.out.println(ropCount);
long end = System.currentTimeMillis();
System.out.println("一百万条数据用时:" + (end-start)/1000 + "s");

Insert picture description here
harm! It may be that my own merging algorithm is not good, and it takes one minute for one million pieces of data. . .

I changed it again. The one-time merge algorithm above uses time to change space. It has always been operated in arr and requires constant movement of elements, so it takes a lot of time.

The idea of ​​improvement is to change space for time, use an auxiliary array that is the same as the original array, and use the method of enqueuing large and small to perform a merge.
The improved one-time merge calculation method is as follows:

/**
* 一次计算
 * 
 * @param arr
 * @param left
 * @param mid
 * @param right
 */
public static void calc(int[] arr,int left,int mid,int right) {
    
    
	// 辅助数组 空间换时间
	int[] helper = new int[right-left+1];
	int i = left;
	int j = mid + 1;
	int index = 0;
	while (i <= mid && j <= right) {
    
    
		if(arr[i] <= arr[j]) {
    
    
			helper[index++] = arr[i];
			i++;
		}else {
    
    
			helper[index++] = arr[j];
			// 此时有mid-i+1个数比j位置的数大,即增加mid-i+1个逆序对
			ropCount += mid-i+1;
			j++;
		}
	}
	// 后半部分没搬完
	if(i > mid && j <= right) {
    
    
		System.arraycopy(arr, j, helper, index, right-j+1);
	}
	// 前半部分没搬完
	if(i <= mid && j > right) {
    
    
		System.arraycopy(arr, i, helper, index, mid-i+1);
	}
	System.arraycopy(helper, 0, arr, left, helper.length);
}

Test it with a million pieces of data:

Insert picture description here
Look, the speed has improved qualitatively, so in the era of advanced hardware, don't be stingy and use time for space. Proper use of auxiliary space will greatly increase the speed of the algorithm.

That's it, haha, bye!

Guess you like

Origin blog.csdn.net/L333333333/article/details/105253762