算法之逆序对问题求解

题目:   给出一列数,a1, a2,....到 an,求它的逆序对数。逆序对就是 下标 i 比 j小,但是值 ai 却比 a j大。n 可以高大 10万。

思路:

(1)穷举,肯定不现实的,因为n 可以高达10万,肯定超时;

(2)考录分治法,受到归并排序的启发,能不能不断划分数组到最小,然后合并时统计 逆序对数。划分和递归都和归并排序没什么区别,问题在合并时如何统计。

合并左右两个数组时,左边 的数组的下标肯定要比右边数组的下标小,那么如果右边数组有比左边数组小的值,比如 [ 5,6] 和 [ 1 ] 合并,那么 5和6 肯定就是1的逆序对组合数了。因此,在每次把右边数组移入临时数组前,左边数组的个数就是该移入数的逆序对数。

代码:

/**
 * @author snail
 * @time 2014-9-11下午09:03:03
 * TODO
 */
public class SecondMerge {
	private static int count = 0; //统计数组中的逆序对数

	public static void main(String[] args) {
		int[] test = {1212,99,6,4};

		SecondMerge.partition(test);
		System.out.println(count+"对 ");
		System.out.println(" ");
		for (int i : test) {
			System.out.print(i+" ");
		}
	}

	/**
	 * decription: 划分
	 * @author : linjq
	 */
	private static void partition(int[] list){
		int length = list.length;
		if (length <= 1) {
			return ;
		}

		int firstLength = length >> 1 ;
		int[] firstHalf = new int[firstLength];
		System.arraycopy(list,0,firstHalf,0,firstLength);
		//继续二分
		partition(firstHalf);

		int secondLength = length - firstLength;
		int[] secondHalf = new int[secondLength];
		System.arraycopy(list,firstLength,secondHalf,0,secondLength);
		partition(secondHalf);

		//合并
		int[] resultList = merge(firstHalf,secondHalf);
		System.arraycopy(resultList,0,list,0,resultList.length);
	}

	/**
	 * decription:合并
	 * @author : linjq
	 */
	private static int[] merge(int[] firstList,int[] secondList){
		int firstLength = firstList.length;
		int secondLength = secondList.length;
		int i = 0,j=0,k=0;

		int[] resultList = new int[firstLength + secondLength];
		while( i<firstLength && j < secondLength  ){
			if(firstList[i] < secondList[j]){

				resultList[k++] = firstList[i++];
			}else{
				//此时,左边还没来得及复制到临时数组中的元素,就是下标比右边小,值却比右边大的逆序值
				count += (firstLength -i);
				resultList[k++] = secondList[j++];
			}
		}
		while(i<firstLength){
			resultList[k++] = firstList[i++];

		}
		while(j < secondLength){

			resultList[k++] = secondList[j++];
		}
		return resultList;
	}

}
时间: 2024-10-20 17:25:17

算法之逆序对问题求解的相关文章

算法之逆序对

算法之逆序对 逆序对问题 ? 假设A[1..n]是一个有n个不同数的数组.若iA[j],则对偶(i, j)称为A的一个逆序对(inversion). 列出数组{2, 3, 8, 6, 1}的5个逆序对 由集合{1, 2, ..., n}中的元素构成的什么数组具有最多的逆序对?它有多少逆序对? 插入排序的运行时间与输入数组中的逆序对的数量有什么关系? 给出一个求在n个元素的任何排列中逆序对数量的算法,最坏时间复杂度为: \(\Theta\)(nlgn) 根据定义易得,逆序对为:(2, 1).(3,

笔试算法题(32):归并算法求逆序对 &amp; 将数组元素转换为数组中剩下的其他元素的乘积

出题:多人按照从低到高排成一个前后队列,如果前面的人比后面的高就认为是一个错误对: 例如:[176,178,180,170,171]中的错误对 为 <176,170>, <176,171>, <178,170>, <178,171>, < 180,170>, <180,171>. 现在要求从一个整数序列中找出所有这样的错误对: 分析: 逆序对(Inversion Pair):在N个可判断大小的数中,逆序对的数量为[0,n(n-1)/2

第二章 算法基础 思考题2-4(逆序对)

1 package chap02; 2 3 import static org.junit.Assert.*; 4 5 import java.util.Arrays; 6 7 import org.junit.Test; 8 9 public class ques2_4 { 10 /** 11 * 逆序对,将一个序列中的所有逆序对打印输出 12 * 13 * @author xiaojintao 14 * 15 */ 16 static void printReverseOrder(int[]

Day2:T4求逆序对(树状数组+归并排序)

T4: 求逆序对 A[I]为前缀和 推导 (A[J]-A[I])/(J-I)>=M A[j]-A[I]>=M(J-I) A[J]-M*J>=A[I]-M*I 设B[]=A[]-M*(); B[J]>=B[I] 也就是求逆序对: 求逆序对的方法主要有两种: 归并排序: 树状数组: 这里两种方法都学习一下: 1.之前对于树状数组的印象就只有单点修改和区间求和 一直觉得lowbit是一个神奇的东西(至今没有搞懂原理) 上网搜了一下用树状数组求逆序对的方法,发现有一个大神写的很棒....看

HDU 4911 http://acm.hdu.edu.cn/showproblem.php?pid=4911(线段树求逆序对)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 解题报告: 给出一个长度为n的序列,然后给出一个k,要你求最多做k次相邻的数字交换后,逆序数最少是多少? 因为每次相邻的交换操作最多只能减少一个逆序对,所以最多可以减少k个逆序对,所以我们只要求出原来的序列有多少个逆序对然后减去k再跟0取较大的就可以了. 因为数据范围是10的五次方,所以暴力求肯定会TLE,所以要用n*logn算法求逆序对,n*logn算法有几种可以求逆序对的: 线段树,树状数

利用merge sort寻找逆序对

算法导论第二章 练习题,使用合并排序算法寻找逆序对 基本思想: 在merge过程中,交换位置与一组逆序对是一一对应的. 在左右两个子数组内部是排好序的,所以逆序对的出现仅仅存在于“左数组中的数组大有右数组中的数字”的情况. 所以在每次的merge过程中就可以进行逆序对的计数. java代码实现: 1 public class InversionCount { 2 public static void main(String[] args){ 3 int[] arr = new int[]{2,3

编程算法 - 数组中的逆序对 代码(C)

数组中的逆序对 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 在数组中的两个数字如果前面一个数字大于后面的数字, 则这两个数字组成一个逆序对. 输入一个数组, 求出这个数组中的逆序对的总数. 使用归并排序的方法, 辅助空间一个排序的数组, 依次比较前面较大的数字, 算出整体的逆序对数, 不用逐个比较. 时间复杂度: O(nlogn) 代码: /* * main.cpp * * Created on: 2014.6.12 * Author:

hdu 5273 Dylans loves sequence(区间逆序对数-莫队算法)

n<=1000,q<=100000,求区间内逆序对数,从[l,r]显然可以log(n)的时间内移动到[l-1,r],[l+1,r],[l,r-1],[l,r+1],那么就可以用莫队进行离线 复杂度大概是O(n*sqrt(n)*log2(n)),不过可以暴力枚举起点,然后向后统计,然后O(1)回答,不过n再大就无法解决了,这个即使是n<=1e5也可以很快得到答案,开-o优化,1e6也可以很快得到答案 #include<bits/stdc++.h> using namespace

【算法32】计算数组中的逆序对

问题描述 设 A[1...n] 是一个数组,如果对于 i < j 有 A[i] > A[j], 则 A[i] 和 A[j] 构成一对逆序.给定一个数组,计算数组中逆序对的个数.例如数组 a[] = {1, 4, 3, 2}, 则 {4, 3} {4, 2} {3, 2}是逆序对,返回 3. 解法一:暴力求解 两个 for 循环枚举所有的数对,如果是逆序对,则 count++,最终返回 count 即可.时间复杂度 O(n^2),代码如下: 1 #include <iostream>