找出兩個整型數組中的公共元素的最大值


一,問題描述

給定兩個整型數組,找出這兩個數組中的最大的公共元素。注意條件:①公共元素   ②最大的公共元素

比如:arr1={8,2,9,6,18,7,25,28}   arr2={6,39,4,9,25,18,36,12}.假設 arr1 的長度為M,arr2的長度為N

這兩個數組的最大公共元素是:25

 

二,思路

①對 arr1 中的每個元素arr1[i],去 arr2 查找是否也存在 該元素,若存在則標記起來,因為它雖然是公共的,但不一定是最大的。

直到掃描完arr1中的所有元素,這種方式的時間復雜度為O(MN),空間復雜度為O(1)

 

②先對數組 arr1 排序,再對 arr2 排序。再定義兩個指針 i, j 分別指向 arr1 和 arr2 中的最后一個元素。比較這兩個數組中的最后一個元素,若相等則找到了所求的元素;若不相等,將指向較大的那個元素的指針 前移一位(減1)。

排序的時間復雜度為O(MlogM + NlogN),最壞情況下指針遍歷的時間復雜度為O(M+N),故總的時間復雜度為O(MlogM+NlogN)

 

③采用 來實現

對兩個數組分別構造兩個大頂堆,若堆頂元素相同,則堆頂元素就是公共最大的元素。否則,刪除較大的那個堆頂元素,進行堆調整,繼續比較。

數組1建堆的時間復雜度為O(M),數組2建堆的時間復雜度為O(N)

一般對於刪除堆頂元素,進行堆調整而言,平均情況下的時間復雜度為O(logN)。故平均情況下,時間復雜度應該要比 方法② 中的小。

另外,可以直接在原數組上進行建堆操作,此時空間復雜度為O(1)

 

三,方法③代碼實現

 核心代碼如下:

 1         int len_1 = arr1.length - 1;
 2         int len_2 = arr2.length - 1;
 3         while(len_1 >= 0 && len_2 >=0)
 4         {
 5             int max1 = arr1[0];//獲取大頂堆的根元素,即數組中的最大值
 6             int max2 = arr2[0];
 7             
 8             if(max1 > max2)//如果arr1的堆頂元素要大,則刪除arr1的堆頂元素
 9             {
10                 swap(arr1, 0, len_1);//delete arr1's root
11                 percDown(arr1, 0, len_1);//進行堆調整, 刪除了最后一個元素,剛好堆調整的元素個數為 len_1
12                 len_1--;
13             }
14             else if( max1 < max2)//如果arr2的堆頂元素要大,則刪除arr2的堆頂元素
15             {
16                 swap(arr2, 0, len_2);
17                 percDown(arr2, 0, len_2);
18                 len_2--;
19             }
20             else//arr1的堆頂元素與 arr2的堆頂元素相等了.
21                 return max1;
22         }

當建立了兩個大頂堆后,比較這兩個大頂堆的堆頂元素,誰大,則刪除誰。當然,刪除了堆頂元素之后,需要進行堆調整以保證堆的性質。

第10行的swap方法就表示 刪除堆頂元素,第11行的percDown方法表示 堆調整。

 

不斷地刪除堆頂元素,直到:①某個堆中的元素都被刪除了(此時 while循環條件不成立了)這表明:兩個數組中沒有公共元素。

②若兩個堆的堆頂元素相同了(第20-21行),則表明找到了最大公共元素。

 

算法的正確性說明:因為使用的是大頂堆。堆頂元素一定是當前數組中最大的元素,而通過比較兩個堆頂元素,若不相等,則刪除較大的堆頂元素,這樣總能保證:優先找到兩個堆中目前相同且最大的元素。

 

完整代碼實現:

//給定兩個整形數組,尋找這兩個數組的公有的且最大的元素
public class MaxCommonEle {

    public static int findCommMax(int[] arr1, int[] arr2)
    {
        if(arr1 == null || arr2 == null)
            throw new NullPointerException();
        if(arr1.length == 0 || arr2.length == 0)
            throw new IllegalArgumentException();
        
        //build heap--大頂堆 , time complex: O(M)
            for(int i = arr1.length / 2 -1; i >= 0; i--)
                percDown(arr1, i, arr1.length);
            
        //build heap, O(N)
        for(int i = arr2.length / 2 - 1; i >= 0; i--)
            percDown(arr2, i, arr2.length);
        
        int len_1 = arr1.length - 1;
        int len_2 = arr2.length - 1;
        while(len_1 >= 0 && len_2 >=0)
        {
            int max1 = arr1[0];//獲取大頂堆的根元素,即數組中的最大值
            int max2 = arr2[0];
            
            if(max1 > max2)//如果arr1的堆頂元素要大,則刪除arr1的堆頂元素
            {
                swap(arr1, 0, len_1);//delete arr1's root
                percDown(arr1, 0, len_1);//進行堆調整, 刪除了最后一個元素,剛好堆調整的元素個數為 len_1
                len_1--;
            }
            else if( max1 < max2)//如果arr2的堆頂元素要大,則刪除arr2的堆頂元素
            {
                swap(arr2, 0, len_2);
                percDown(arr2, 0, len_2);
                len_2--;
            }
            else//arr1的堆頂元素與 arr2的堆頂元素相等了.
                return max1;
        }
        return -1;// -1 means there are no common element
    }
    
    private static void percDown(int[] arr, int i, int n)
    {
        int tmp;
        int child;
        
//        int k = leftChild(i);
        for(tmp = arr[i]; leftChild(i) < n; i = child)
        {
            child = leftChild(i);
            
            if(child != n-1 && arr[child] < arr[child+1])
                child = child + 1;
            if(tmp < arr[child])
                arr[i] = arr[child];
            else
                break;
        }
        arr[i] = tmp;
    }
    
    private static int leftChild(int i){
        return (i << 1 ) + 1;
    }
    
    private static void swap(int[] arr ,int i, int j)
    {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    
    
    //hapjin test
    public static void main(String[] args) {
        int[] arr1 = {8,2,9,6,18,7,25,28};
        int[] arr2 = {6,39,4,9,25,18,36,12};
        
//        int[] arr1 = {4,2,8};
//        int[] arr2 = {10,4,6};

//        int[] arr1 = {4,2,8};
//        int[] arr2 = {5,7,9};
        int res = findCommMax(arr1, arr2);
        System.out.println(res);
    }
}
View Code

 

四,參考資料

數據結構--堆的實現之深入分析


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM