数组中的逆序对数量

思路:
1、由于冒泡排序是对每一次数组遍历中相邻两个存在的逆序对(升序排列时)进行交换,那么完成冒泡排序过程中交换次数就是逆序对存在的个数。
2、利用归并排序的思想[1],将数组递归划分直到只剩各自元素,接下来就是合并过程,由于将数组划分成a[low] - a[mid],a[mid+1] - a[high]两个部分,若前面的某个元素a[i]大于后面的某个元素a[j],那么逆序对个数为 j-(mid+1)+1 = j-mid(首次递归到此处时候只有两个元素,所以相当于前、后均已排好序。更进一步为了维持已经排好序的元素,就要开辟一个新的空间sorted存放排好序的元素),合并的过程中可能出现前或者后其中一个在i、j比较时率先取完,那么还需要对另外一个没有取完的数组(排序好的)继续将其放入到sorted中。利用sorted的原因是防止重复计算逆序对。
实现:

package _数组中逆序对数量;

public class Solution {
	public static void main(String[] args) {
		int[] a = {364,637,341,406,747,995,234,971,571,219,993,407,416,366,315,
				301,601,650,418,355,460,505,360,965,516,648,727,667,465,849,455,
				181,486,149,588,233,144,174,557,67,746,550,474,162,268,142,463,
				221,882,576,604,739,288,569,256,936,275,401,497,82,935,983,583,
				523,697,478,147,795,380,973,958,115,773,870,259,655,446,863,735,
				784,3,671,433,630,425,930,64,266,235,187,284,665,874,80,45,848,38,811,267,575};
		int[] b = {364,637,341,406,747,995,234,971,571,219,993,407,416,366,315,
				301,601,650,418,355,460,505,360,965,516,648,727,667,465,849,455,
				181,486,149,588,233,144,174,557,67,746,550,474,162,268,142,463,
				221,882,576,604,739,288,569,256,936,275,401,497,82,935,983,583,
				523,697,478,147,795,380,973,958,115,773,870,259,655,446,863,735,
				784,3,671,433,630,425,930,64,266,235,187,284,665,874,80,45,848,38,811,267,575};
		int count1 = countByBubbleSort(a);
		int[] sorted = new int[b.length];
		int count2 = countByMergeSort(b, sorted, 0, a.length-1);
		System.out.println(count1);
		System.out.println(count2);
	}

	private static int countByMergeSort(int[] a, int[] sorted, int low, int high) {
		if(low==high) return 0;
		int mid = (low+high) >> 1;
		int leftCount = countByMergeSort(a, sorted, low, mid);
		int rightCount = countByMergeSort(a, sorted, mid+1, high);
		int count = 0;
		int sortedFlag = high;
		int i=mid, j=high;
		while(i>=low&&j>mid) {
			if(a[i]>a[j]) {
				count += j-mid;
				sorted[sortedFlag--] = a[i--];
			}
			else {
				sorted[sortedFlag--] = a[j--];
			}
		}
		for(;i>=low;i--) {
			sorted[sortedFlag--] = a[i];
		}
		for(;j>mid;j--) {
			sorted[sortedFlag--] = a[j];
		}
		for(int k=low;k<=high;k++) {
			a[k] = sorted[k];
		}
		return (leftCount+rightCount+count);
	}

	private static int countByBubbleSort(int[] a) {
		int count = 0;
		for(int i=0;i<a.length-1;i++) {
			for(int j=0;j<a.length-i-1;j++) {
				if(a[j]>a[j+1]) {
					swap(a, j, j+1);
					count++;
				}
			}
		}
		return count;
	}

	private static void swap(int[] a, int i, int j) {
		a[i] = a[i] ^ a[j];
		a[j] = a[i] ^ a[j];
		a[i] = a[i] ^ a[j];	
	}
}

1、https://www.nowcoder.com/questionTerminal/96bd6684e04a44eb80e6a68efc0ec6c5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树状数组(Fenwick tree)是一种用于高效求解数列前缀和(Prefix Sum)问题的数据结构,而求逆序对也是一种经典的问题。 假设有个长度为 n 的数组 a,我们要求其中逆序对数量,即所有 i < j 且 a[i] > a[j] 的 (i,j) 对数。这个问题可以用归并排序的思想求解,但是这里我们介绍一种使用树状数组的解法。 思路如下: 1. 将原数组 a 复制一份并排序,得到新数组 b,将 b 中的每个元素在原数组 a 中的下标记录在数组 c 中。 2. 从右往左遍历 a,对于每个元素 a[i],在树状数组中查询前缀和 sum(c[i]-1),即小于 a[i] 的元素个数,将结果累加到逆序对计数器 ans 中。 3. 将 a[i] 在数组 c 中对应的位置在树状数组中更新为 1。 下面是使用 Python 实现的代码: ```python def lowbit(x): return x & -x def update(bit, x, val): n = len(bit) while x <= n: bit[x] += val x += lowbit(x) def query(bit, x): res = 0 while x > 0: res += bit[x] x -= lowbit(x) return res def count_inversions(a): n = len(a) b = sorted(a) c = {v: i+1 for i, v in enumerate(b)} bit = [0] * (n+1) ans = 0 for i in range(n-1, -1, -1): ans += query(bit, c[a[i]]-1) update(bit, c[a[i]], 1) return ans ``` 其中,lowbit 函数是计算 x 的最低位 1 所代表的值;update 函数是树状数组的更新操作;query 函数是树状数组的查询操作;count_inversions 函数是主函数,用于计算逆序对数量。 时间复杂度为 O(nlogn)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值