編程之美【03】


3、題目:能否快速找出一個數組(簡單起見,數組中元素值各不一樣)中的兩個數字,讓這兩個數字之和等於一個給定的值。

例如,給定數組arr(如下圖),給定值key為12,則arr[0](5)、arr[4](7)滿足要求。

解法一、窮舉法

窮舉說白了就是不斷試,題目為從數組中找兩個滿足條件的數字,即把數組看成兩份,遍歷第一份中的所有去第二份里面找是否存在滿足條件的數字。

思路:窮舉數組中任意的兩兩組合,並計算取出的兩個數之和是否等於給定值即可,通過窮舉計算時間復雜度為O(N * N)。對於求和計算具有的對稱性,當遍歷數組取出數據時,只需向后取值即可(如下圖)。

算法:

1、遍歷數組,從第一個至最后一個,依次取出數組中的元素A;

2、遍歷該元素所在位置后的元素B,計算A + B是否等於給定值,直至相等;

代碼:

    public int[] getPairsFromArray(int[] arr, int key) {
        int[] partner = new int[2];
        boolean isPartnerIn = false;
        for (int i = 0; i < arr.length && !isPartnerIn; i++) {
            for(int j = i + 1; j < arr.length && !isPartnerIn; j++) {
                if(arr[i] + arr[j] == key) {
                    partner[0] = arr[i];
                    partner[1] = arr[j];
                    
                    isPartnerIn = true;
                }
            }
        }
        
        return isPartnerIn ? partner : new int[0];
    }

窮舉法——改進版(感謝  @ck_winner 提供的思路)

思路:以給定值的二分之一(part)為分割數,將數組分割成兩部分,其中,左部分小於part值,右邊部分大於part值。由於本題中數組中的元素值不同,則如存在兩個數之和為給定數,則這兩個數必分屬左邊和右邊部分,再通過上面的窮舉方式進行查找即可。具體過程可見下圖:

算法:

1、通過給定數值的二分之一作為分割數,將數組分割成左右兩部分;

2、遍歷左部分數值A,右部分數值B,計算A + B是否等於給定值,直至相等;

    private int partition(int[] arr, int key) {
        int tmp = 0;
        int i = 0, j = arr.length - 1;
        while(true) {
            while(i < arr.length && arr[i] <= key) 
                i++;
            while(j >= 0 && arr[j] > key)
                j--;
            
            if(i >= j) 
                break;
            
            //swap arr[i] and arr[j]
            tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
        
        return j;
    }
    public int[] getPairsFromArray4(int[] arr, int key) {
        int[] partner = new int[2];
        
        boolean isPartnerIn = false;
        int part = partition(arr, key / 2);
        for(int i = 0; i <= part && !isPartnerIn; i++) {
            for(int j = part + 1; j < arr.length && !isPartnerIn; j++) {
                if(arr[i] + arr[j] == key) {
                    partner[0] = arr[i];
                    partner[1] = arr[j];
                    
                    isPartnerIn = true;
                }
            }
        }
        
        return isPartnerIn ? partner : new int[0];
    }

解法二、無序變有序

將無序數組有序化是處理無序數組常用方法,有序數組有較多較好的處理方法,如雙端遍歷,二分查找等,通過這些方法可以使處理過程變得簡化。

思路:先將無序數組有序化(通過快排方式,計算時間復雜度為O(N * log N)),排序后可采用雙向數組遍歷方式(如下圖)。若arr[i] + arr[j]等於給定值Key,直接返回;若arr[i] + arr[j]小於給定值key,則i向后位移一位;若arr[i] + arr[j]大於給定值key,則j向前位移一位。計算時間復雜度為O(N * log N + N);

計算:

1、通過快排算法將無序數組有序化;

2、采用雙端遍歷方式,設置i和j分別為數組兩端index;若arr[i] + arr[j] = Key,返回結果;若arr[i] + arr[j] < key,i++;若arr[i] + arr[j] > key,j--;

代碼:

    public int[] getPairsFromArray2(int[] arr, int key) {
        Arrays.sort(arr);
        
        int[] partner = new int[2];
        boolean isPartnerIn = false;
        for (int i = 0, j = arr.length - 1; i < j && !isPartnerIn; ) {
            if ((arr[i] + arr[j]) == key) {
                partner[0] = arr[i];
                partner[1] = arr[j];
                
                isPartnerIn = true;
            } else if((arr[i] + arr[j]) < key) {
                i++;
            } else {
                j--;
            }
        }
        
        return isPartnerIn ? partner : new int[0];
    }

解法三、Hash表

之前討論過bitmap,關系映射表等,形式雖然多樣,實則都為空間換時間的方法,通過構造空間位置(key)與值(value)的映射關系,使得通過空間位置(key)取值(value)時間復雜度為O(1)。

思路:將數組中的元素放入bitmap中,然后再遍歷數組中的所有元素,判定bitmap中給定元素值-數組元素值位置是否存在。由於bitmap取值時間復雜度為O(1),整個計算時間復雜度為O(N),構造bitmap需要空間為O(M),其中M為數組最大數;

計算:

1、構造bitmap表,將數組中所有元素放入bitmap表中;

2、再次遍歷數組中所有元素,並判斷bitmap表中key-arr[i]是否存在;

代碼:

    public int[] getPairsFromArray(int[] arr, int key) {
        BitSet bs = new BitSet();
        for(int i = 0 ; i < arr.length; i++) {
            bs.set(arr[i]);
        }
        
        int[] partner = new int[2];
        boolean isPartnerIn = false;
        for (int i = 0; i < arr.length && !isPartnerIn; i++) {
            if (bs.get(key - arr[i]) && (key - arr[i]) != arr[i]) {
                partner[0] = arr[i];
                partner[1] = key - arr[i];
                
                isPartnerIn = true;
            }
        }
        
        return isPartnerIn ? partner : new int[0];
    }

 

 

 

 


免責聲明!

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



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