分治算法题:nlgn时间复杂度计算原序列的重要逆序个数

编程入门 行业动态 更新时间:2024-10-23 15:27:37

题目描述:

Recall the problem of finding the number of inversions. As in the text, we are given a sequence of n numbers a1, ... , an, which we assume are all distinct, and we define an inversion to be a pair i< j such that ai>aj.  
We motivated the problem of counting inversions as a good measure of how different two orderings are. However, one might feel that this measure is too sensitive. Let’s call a pair a significant inversion if i< j and ai> 2aj. Given an O(nlogn) algorithm to count the number of significant inversions between two orderings.

我的理解:让我们求一个序列的significant inversion个数,这个不同于一般的逆序数,但是求的思想是一样的,都是采用分治法和归并排序的算法实现。但是不同于普通的求逆序数算法,如果是求ai>aj的个数的话,可以在计算合并子序列的逆序数个数的过程中顺便排序。因为如果不满足ai>aj的话,那就将aj放入tmp序列中,继续比较ai和a(j+1)的大小。

在思考多久之后,决定在函数merge的实现中,将计算合并的过程中产生的重要逆序数和给这个合并子序列排序分开用两个while循环实现。具体实现看代码。

#include<iostream>
#include<stdio.h>
#include<cmath> 
#include<string>
#include<string.h>
#include<set>
#include<map>
#include <algorithm>
using namespace std;

/*使用分治法和归并排序的思想来算逆序数,nlgn复杂度,同时完成了对原序列的排序*/ 
//合并A[left]-A[mid]和A[mid+1]-A[right] 
int merge(int A[], int left, int mid, int right) {
	int *tmp = new int[right-left+1];
	int ret = 0;
	int i = left, j = mid + 1,cnt = 0;
	int k = mid - left + 1;
	/*计算满足题意的逆序数个数*/
	while (i <= mid && j <= right) {
		if(A[i] > 2 * A[j]) {
			ret += k;
			j++;
		}
		else{
			k--;
			i++;
		}
	}
	/*给子序列合并排序*/
	i = left, j = mid + 1;
	while (i <= mid && j <= right) {
		if(A[i] > A[j]) {
			tmp[cnt++] = A[j];
			j++;
		}
		else{
			tmp[cnt++] = A[i];
			i++;
		}
	}
	while (i <= mid) {
		tmp[cnt++] = A[i];
		i++;
	}
	while (j <= right) {
		tmp[cnt++] = A[j];
		j++;
	}
	//至此,tmp为合并后排好序的序列 ,接下来将tmp的值复制给A
	for (k = 0; k < right - left + 1; k++) {
		A[left + k] = tmp[k];
	} 
	delete []tmp;
	return ret;
}

int inversionCount(int A[], int left, int right) {
	if(left >= right) return 0;
	int mid = (left + right) / 2;
	int num1 = inversionCount(A, left, mid);
	int num2 = inversionCount(A, mid+1, right);
	return num1+num2+merge(A, left, mid, right);
} 

int main() {
	int n, num[100];
	while(scanf("%d", &n) == 1) {
		for (int i = 0; i < n; i++) scanf("%d", num + i);
		int res = inversionCount(num, 0, n - 1);
		/*输出重要逆序数个数*/ 
		printf("%d\n", res);
		/*遍历输出排好序的序列*/ 
		for (int i = 0; i < n-1; i++) printf("%d ", num[i]);
		printf("%d\n", num[n-1]);
	}
	
	return 0;
} 


更多推荐

分治算法题:nlgn时间复杂度计算原序列的重要逆序个数

本文发布于:2023-06-13 09:38:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/679063.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:逆序   复杂度   序列   算法   个数

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!