【算法导论学习-011】数组中的逆序对个数(Counting inversions in an array)

1、问题来源
《算法导论》P41思考题2-4:Let A[1..n] be an array of n distinct numbers. (i, j) is called an inversion of A if i < j and A[i] > A[j]. 
2、解决方案
方案1:不排序的双重循环(时间复杂度O(n^2))
 public static int getInversions(int[] array) {
        int counter=0;
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i]>array[j]) {
                    counter++;
                }
            }
        }
        return counter;
       
    }
方案2:归并排序过程中计算逆序对(《算法导论》提示的方法,复杂度O(nlgn))
以下过程图解请参照《算法导论》P35页,注意对比本博客中【算法导论学习-002】归并排序(MergeSort)的异同。
<span style="font-size:18px;">/** 
 * 创建时间:2014年8月10日 下午4:12:19 
 * 项目名称:Test 
 * @author Cao Yanfeng 
 * @since JDK 1.6.0_21 
 * 类说明: 
 */
public class CountInversionsTest {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] array={5,2,4,7,1,3,2,6};
//      int result=getInversions(array);
        int result=mergeSort(array, 0, array.length-1);
        System.out.println(result);
       
 
    }
    public static int mergeSort(int[] arr, int start, int end) {
        if (start < end) {
            int middle = (start + end) >>> 1;
         </span><span style="font-size:18px;color:#cc0000;"><strong>   int l=mergeSort(arr, start, middle);
            int r=mergeSort(arr, middle + 1, end);
            int m=mymerge(arr, start, middle, end);
            return l+r+m;
        }else {
            return 0;</strong></span><span style="font-size:18px;">
        }
    }
 
    /*
     * 归并排序的思路:首先将arr分成两部分,用leftArray和rightArray暂存,然后从头开始比较leftArray和rightArray,
     * 谁小谁放入arr,相应指针移动
     * 小技巧:leftArray和rightArray都增多最后一位,存放Integer.MAX_VALUE,用于不让它移动到最后
     */
    public static int mymerge(int[] arr, int start, int middle, int end) {
        /*拆分数组为leftArray和rightArray*/
        int leftArrayLength = middle - start + 1;
        int rightArrayLength = end - middle;
        int[] leftArray = new int[leftArrayLength + 1];//多一位
        int[] rightArray = new int[rightArrayLength + 1];//多一位
        for (int i = 0; i < leftArrayLength; i++) {
            leftArray[i] = arr[start + i];
        }
        for (int i = 0; i < rightArrayLength; i++) {
            rightArray[i] = arr[middle + 1 + i];
        }
        /*多的最后一位记得要赋最大值*/
        rightArray[rightArrayLength] = Integer.MAX_VALUE;
        leftArray[leftArrayLength] = Integer.MAX_VALUE;
        /*算法的关键部分,左右指针移动*/
        int j = 0;
        int k = 0;
       </span><strong style="font-size: 16px;"><span style="color:#993300;"> int number=0;</span></strong><span style="font-size:18px;">
        for (int i = start; i <= end; i++) {
            if (leftArray[j] </span><span style="color:#cc0000;font-size: 16px;"><strong><=</strong></span><span style="font-size:18px;"> rightArray[k]) {
                arr[i] = leftArray[j];
                j++;
            } else {
                arr[i] = rightArray[k];
                k++;
               </span><span style="color:#990000;font-size: 16px;"><strong> number+=leftArrayLength-j;</strong></span><span style="font-size:18px;">
            }
        }
        return number;
 
    }
 
}</span>
方案3:制作数组排序后的副本,利用原数组每个元素在副本中进行二分搜索(复杂度O(nlgn)​
    例如: int[] array={5,2,4,7,1,3,2,6};
    制作排序后的副本​  int[] temp={1,2,2,3,4,5,6}
    array[0]=5,在temp中二分搜索,得到下表index=5,比它小的有inversions=​index-0=5个
    temp​去除5,int[] temp={1,2,2,3,4,6}​
    array[1]=2,同理inversions=​index-0=1个​
    同理,对于之后的inversions分别是 3,4,1​,0,,0,总计5+1+3+4+1=14个
*******************************************************************************************************************************************************
最后说明,对于一系列数来说,他们的所有排列的逆序对的期望是:n(n-1)/4。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值