排序問題思考(要求時間和空間複雜度儘量的低)【Part 1】

題目:java

有一個無序整型數數組,如何求出這個數組排序後的任意兩個相鄰元素的最大差值?要求時間和空間複雜度儘量低。(例如:無序數組 二、三、一、四、6,排序後是一、二、三、四、6,最大差值是 6-4=2)算法

 

 

解題思路分析:數組

用一種較快的穩定排序算法(好比歸併算法,時間複雜度N*logN)給原數組排序,而後遍歷排好序的數組,每兩個相鄰元素求差,最終獲得最大差值。 測試

該解法的時間複雜度是O(N*logN),在不改變原數組的狀況下,空間複雜度是O(N)。this

 

可是,這個題的本意,其實不是純粹的排序問題spa

 

要處理這個問題,能夠從要求上出發考慮,即什麼排序算法的時間複雜度比O(N*logN)還要低? 嗯,從這點出發,彷佛能夠找到答案,回顧排序算法,比歸併算法還要快的,是計數排序以及桶排序算法了。code

 

那下面,就先從計數排序開始分析:對象

1.利用計數排序的思想,先求出原數組的最大值Max與最小值Min的區間長度k(k=Max-Min+1)。 blog

2.建立一個長度爲k的新數組Array。 排序

3.遍歷原數組,把原數組每個元素插入到新數組Array對應的位置,好比元素的值爲n,則插入到Array[n-min]當中。此時Array的部分位置爲空,部分位置填充了數值。 

4.遍歷新數組Array,統計出Array中最大連續出現空值的次數+1,即爲相鄰元素最大差值。

例如給定無序數組 { 二、六、三、四、五、十、9 },處理過程以下圖:

 

 

該解法的時間複雜度爲O(n+k),空間複雜度一樣是O(n+k)。

 

下面看看其java代碼實現過程:

  1 /**
  2  * @author "shihuc"
  3  * @date   2017年1月11日
  4  */
  5 package jishuSort;
  6 
  7 import java.io.File;
  8 import java.io.FileNotFoundException;
  9 import java.util.Arrays;
 10 import java.util.Scanner;
 11 
 12 /**
 13  * @author chengsh05
 14  *
 15  */
 16 
 17 class MaxMin {
 18     int max;
 19     int min;
 20     /**
 21      * @return the max
 22      */
 23     public int getMax() {
 24         return max;
 25     }
 26     /**
 27      * @param max the max to set
 28      */
 29     public void setMax(int max) {
 30         this.max = max;
 31     }
 32     /**
 33      * @return the min
 34      */
 35     public int getMin() {
 36         return min;
 37     }
 38     /**
 39      * @param min the min to set
 40      */
 41     public void setMin(int min) {
 42         this.min = min;
 43     }
 44 }
 45 
 46 public class Algorithm {
 47 
 48     /**
 49      * @param args 
 50      */
 51     public static void main(String[] args) {
 52         
 53         File file = new File("./src/jishuSort/sample.txt");
 54         Scanner sc = null;
 55         try {
 56             sc = new Scanner(file);
 57             int N = sc.nextInt();
 58             for(int i=0; i<N; i++){
 59                 int S = sc.nextInt();
 60                 int data[] = new int[S];
 61                 for(int j=0; j<S; j++){
 62                     data[j] = sc.nextInt();
 63                 }
 64                 MaxMin mm = getMaxMin(data);
 65                 int mArr[] = getMinusArray(data, mm);
 66                 int minus = getTarget(mArr, mm.getMin() - 1);
 67                 System.out.println(i + " -- >  " + minus);                
 68             }            
 69         } catch (FileNotFoundException e) {
 70             // TODO Auto-generated catch block
 71             e.printStackTrace();
 72         } finally {
 73             if(sc != null){
 74                 sc.close();
 75             }
 76         }        
 77     }
 78     
 79     /**
 80      * 在時間複雜度爲O(n)狀況下,計算出最大值與最小值
 81      * 
 82      * @param da
 83      * @return
 84      */
 85     public static MaxMin getMaxMin(int da[]){
 86         MaxMin mm = new MaxMin();
 87         int max = Integer.MIN_VALUE;
 88         int min = Integer.MAX_VALUE;
 89         for(int i=0; i<da.length; i++){
 90             if(da[i] > max){
 91                 max = da[i];
 92             }
 93             if(da[i] < min){
 94                 min = da[i];
 95             }
 96         }
 97         
 98         mm.setMax(max);
 99         mm.setMin(min);
100         return mm;
101     }
102     
103     /**
104      * 獲取最大值與最小值之間的距離 k
105      * 
106      * @param mm
107      * @return k
108      */
109     public static int getDistance(MaxMin mm){
110         return mm.getMax() - mm.getMin() + 1;
111     }
112     
113     /**
114      * 獲取差值數組,即原數組中的每一個數與最小值的差值位置處放置原數組的元素
115      * 
116      * @param da 原數組
117      * @param mm 最大最小值對象
118      * @return 差值數組
119      */
120     public static int[] getMinusArray(int da[], MaxMin mm){
121         int K = getDistance(mm);
122         int min = mm.getMin();
123         
124         int minusArray[] = new int[K];
125         //將數組初始化爲全mm.getMin() - 1的值, 假設,這裏的mm.getMin()比Integer.MIN_VALUE大,本身分析
126         Arrays.fill(minusArray, mm.getMin() - 1); 
127         
128         for(int i=0; i<da.length; i++){
129             int n = da[i];
130             minusArray[n - min] = n; 
131         }
132         
133         return minusArray;
134     }
135     
136     /**
137      * 找出連續出現空值的最大個數,注意,是兩個數之間的差距,因此,最後要補加一個1    
138      * 
139      * @param minusArr
140      * @param empty
141      * @return
142      */
143     public static int getTarget(int minusArr[], int empty){
144         int size = 0;
145         int temp = 0;
146         for(int i=0; i<minusArr.length; i++){
147             if(minusArr[i] == empty){
148                 temp++;
149             }else{
150                 if(temp > size){
151                     size = temp;                    
152                 }
153                 temp = 0;
154             }
155         }
156         return size + 1;
157     }
158 }

附加程序中用到的測試數據sample.txt:

1 2
2 7
3 2 6 3 4 5 10 9
4 5
5 2 3 1 4 6

數據中第一行,表示有多少個測試案例,後續每兩行表示一個測試裏,上一行是測試數組元素個數,下一行表示數組元素的內容。

 

測試運行後的結果以下:

1 0 -- >  3
2 1 -- >  2

 

今天,就只說到這裏吧,僅僅將計數排序實現了下,裏面有個注意的地方,就是如何判斷差值數組的內容是空,請讀者自行分析。

 

後續將補充桶排序的實現方案!

相關文章
相關標籤/搜索