编程之美-快速寻找满足条件的2 个数

能否快速找出一个数组中的两个数字,让这个两个数字之和等于一个给定的值,为了简化起见,我们假设这个数组中肯定至少存在一组满足要求的解。

作者给出了3种方案:

[方案一]穷举法:从数组任意取出两个数字,计算两者之和是否为给定的数字。时间复杂度O(N^2),效率较低。

[方案二]将问题变通为一个查找问题:求两个数之和,假定为sum。对于数组中的每个数array[i],判断sum-array[i]是否在数组中。在一个无序数组中查找一个数的复杂度是O(N),对于每个数字都要进行相应的查找,则时间复杂度仍为O(N^2)。为了提高效率,可以相对数组进行排序,然后利用二分查找算法,时间复杂度为O(NlogN)。

[方案三]利用hash表提高查找效率,因为给定一个数字,根据hash映射查找另一个数字是否在数组中,只需用O(1)的时间,查找时间为O(1),总的时间复杂度就为O(N)。但是这会使得空间复杂度也为O(N)。

[方案四]先对数组进行排序,然后对数组中的两个数之和进行一个有序的遍历。具体算法:先令i=0,j=n-1,判断array[i]+array[j]是否等于sum,如相等则结束;如小于则i向右移动一个位置,否则j向左移动一个位置。这样时间复杂度为排序O(NlogN)+查找O(N) = O(N(logN+1))

[扩展问题1]:如果将“两个数字”改为“三个数字”或“任意个数字”时,如何求解?

[方案]对于“三个数字”其实就是对于数组中的每个数字array[i]判断数组中的其他数字是否存在两个数字的和为sum-array[i],以此递归下去。

int index = 0;
bool find(int array[], int n, int start, int m, int sum, int result[]){
    assert(m >= 2);
    if(n-start < m)
        return false;
    int i,j;
    if(m == 2){
        for(i=start,j=n;i<j;){
            if(array[i] + array[j] == sum){
                result[index++] = array[i];
                result[index++] = array[j];
                return true;
            }
            else if(array[i] + array[j] < sum)
                i++;
            else
                j--;
        }
        return false;
    }else{
        for(i=start;i<n;i++){
            result[index++] = array[i];
            if(find(array,n,i+1,m-1,sum - array[i],result)){
                return true;
            }
            index--;
        }
        return false;
    }
    return false;
}

[扩展问题2]:如果完全相等的一对数字找不到,能否找出和最接近的解? 算法实现(C语言):

void findNearest(int array[], int n, int sum, int result[]){
    int i,j;
    int minDiff = INT_MAX;
    for(i=0,j=n-1;i<j;){
        if(array[i]+array[j] == sum){
            result[0] = array[i];
            result[1] = array[j];
            return;
        }else{
            int diff = array[i]+array[j] -sum;
            int tmp_i = array[i];
            int tmp_j = array[j];
            if(diff > 0)
                j--;
            else{
                i++;
                diff = -diff;
            }
            if(diff < minDiff){
                minDiff = diff;
                result[0] = tmp_i;
                result[1] = tmp_j;
            }
        }
    }
}

转自:http://blog.csdn.net/andyliuxs/article/details/7537128

给定一个数N和一组数字集合S,在S中找到和最接近N的子集。

更多:http://blog.csdn.net/wxl3105/article/details/7651579

原文地址:https://www.cnblogs.com/youxin/p/3367398.html