算法之逆序对问题求解


题目:   给出一列数,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;
	}
	
	
	
}









  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值