归并法求逆序数之“Ultra-QuickSort”

题目大意:

  给你一个上限为(5e5)的整数 n 。

  在给出 n 个非负整数,这些数上限是 999 999 999 。

  求出其中有多少个逆序数对。

  解释下逆序数对:

    比如在数列 1 ,2 ,5 ,4 ,3 中,

    1 的逆序数就是后面所有比它小的数字个数,即为 0 。

    2 同理 ,即为 0 。

    5 后面有 3 和 4 ,即为 2 。

    4 后面有一个 3 ,即为 1 。

    3 后面没有数字,即为 0 。

    所以在上述数列中,逆序数对有  0 + 0 + 2 + 1 + 0 == 3  个。

解题思路:

  在归并的过程中检测单向移动距离之和(所谓单向  就是要么都计算往前移动的距离,要么相反,计算往后移动的距离)。

  比如 3  ,2 ,4 ,1 。(检查数字向前移动的距离和)

  第一步:3 和 2 调换 ,检查 3 向前移动了 1 个单位,数列变成:  2  3  4  1  

  第二步:4 和 1 调换 ,检查 4 向前移动了 1 个单位 ,数列变成:  2  3  1  4

  第三步:归并两个子数列 ,发现只有 1 向前移动了两个单位,而后再也不出现向前移动的数字,数列也变成最终的有序数列。

  如果计算向后移动的距离和也是同理:

    3 移动 1 个单位 , 4 移动 1 个单位 , 2 移动 1 个单位 , 3 又移动 1 个单位。

    加起来也是正好 4 个单位。

  所以这个数列的逆序数对就是 4 ,输出换行即可。

AC代码:

 1 import java.util.*;
 2 
 3 public class Main{
 4 
 5     static long ans = 0L;
 6     static int num[] = new int[500005];
 7     static int temp[] = new int[500005];
 8 
 9     static void merge(int low,int mid,int high){
10         int i = low; int j = mid + 1; int k = low;
11         while(i <= mid && j <= high){  
12             if (num[i] <= num[j]){  
13                 temp[k ++] = num[i ++];  
14             }  
15             else{  
16                 ans = ans + j - k ;
17                  temp[k ++] = num[j ++];  
18             }  
19         }  
20         while (i <= mid) {temp[k ++] = num[i ++];}  
21         while (j <= high){temp[k ++] = num[j ++];}  
22             for(i = low; i <= high; ++i){  
23                 num[i] = temp[i];  
24             }  
25     }
26     
27     static void sort(int a,int b){
28         if(a < b){
29             int mid = (a + b) / 2;  
30             sort(a, mid);  
31             sort(mid + 1, b);  
32             merge(a, mid, b);    
33         }
34     }
35     
36     public static void main(String[] args){
37         Scanner sc = new Scanner(System.in);
38         while(sc.hasNext()){
39             int n = sc.nextInt();
40             if(n == 0){break;}
41             for(int i = 0;i < n;i ++){
42                 num[i] = sc.nextInt();
43             }
44             sort(0,n - 1);
45             System.out.println(ans); 
46             ans = 0L;
47         }
48     }
49 }

  此处再给出一个超时的代码,不过这个程序可以查看计算过程和排序过程,具体超时原因应该是出现了无用遍历。

超时代码:

 1 import java.util.*;
 2 
 3 public class Main{
 4     
 5     static int ans = 0;
 6     
 7     static void print(int x[]){  
 8         for(int i = 0; i < x.length; i++){  
 9                     System.out.print(x[i] + "  ");  
10                }System.out.println();  
11         }
12 
13     static void mergeSort(int x[]){  
14         sort(x,0,x.length - 1);  
15     }
16 
17 
18     static void sort(int arr[], int left, int right){  
19         if (left >= right){return; } 
20             int mid = (left + right) / 2;   
21                sort(arr, left, mid);  
22             sort(arr, mid + 1, right);   
23             merge(arr, left, mid, right);  
24             //print(data); 
25         }  
26 
27     static void merge(int Array[], int index_L, int index_C, int index_R){  
28             int Array_t[] = new int[Array.length];   
29             int mid = index_C + 1;   
30             int index_t = index_L;    
31             int _t = index_L;  
32             while (index_L <= index_C && mid <= index_R){    
33                     if (Array[index_L] <= Array[mid]){  
34                         Array_t[index_t ++] = Array[index_L ++];  
35                     } 
36             else{  
37                 //System.out.println(mid - index_t);
38                     ans = ans + mid - index_t;
39                 //System.out.println("ans " + ans);
40                            Array_t[index_t ++] = Array[mid ++];  
41                     }  
42             }  
43             while (mid <= index_R) {  
44                     Array_t[index_t ++] = Array[mid ++];  
45             }  
46             while (index_L <= index_C) {  
47                     Array_t[index_t ++] = Array[index_L ++];  
48             }    
49             while (_t <= index_R) {  
50                     Array[_t] = Array_t[_t ++];  
51             }  
52     }  
53 
54     public static void main(String[] args){
55         Scanner sc = new Scanner(System.in);
56         while(sc.hasNext()){
57             int n = sc.nextInt();
58             if(n == 0){break;}
59             int in[] = new int[n];
60             for(int i = 0;i < n;i ++){
61                 in[i] = sc.nextInt();
62             }
63             //print(in);
64             mergeSort(in);
65             //print(in);
66             System.out.println(ans); 
67             ans = 0;
68         }
69     }
70 }

 

转载于:https://www.cnblogs.com/love-fromAtoZ/p/7591651.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值