编程之美【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];
    }

 

 

 

 

posted @ 2013-01-17 01:24  @小小鸟@  阅读(2378)  评论(16编辑  收藏  举报