您的位置:首页 > 其它

寻找满足和为定值的两个数

2014-09-26 08:04 218 查看
参考:http://blog.csdn.net/v_JULY_v/article/details/6419466
https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/02.03.md
上面是大牛,我现在也是对着他的博客系列一篇篇在学习
寻找满足和为定值的两个数
一、算法思想:

例如对于给定数组 {1、2、4、7、11、15} 和 sum = 15,要求我们找出数组中满足和为sum的一对数。在有序和无序情况下,处理起来有所分别。O(n2)暴搜我就不说了
1、排序+二分查找
我们可以穷举第一个数,那对于第二个数如何确定?可以通过排序后进行二分查找获得。这样的时间复杂度是O(nlogn) 空间复杂度是O(1)
vector<int> twoSum_v1(int a[], int n, int sum)
    {
        sort(a, a+n);
        vector<int> res;
        for(int i = 0; i < n; ++ i)
        {
            int x = sum - a[i];
            int left = i + 1, right = n - 1, mid;
            while(left <= right)
            {
                mid = (left + right) / 2;
                if(a[mid] == x) break;
                else if(a[mid] < x) left = mid + 1;
                else right = mid - 1;
            }
            if(left <= right)
            {
                res.push_back(a[i]);
                res.push_back(a[mid]);
                break;
            }
        }
        return res;
    }


2、哈希表,这里用C++的unorder_map
同样循环每次确定第一个数a[i],然后利用hash表查找sum-a[i]是否在数组中。利用哈希表一个好处就是不用排序, 时间复杂度也降到了 O(n),但是需要 的空间复杂度O(n)
//unorder_map  哈希表实现
    vector<int> twoSum_v2(int a[], int n, int sum)
    {
        unordered_map<int,bool> exist;
        vector<int> res;
        for(int i = 0; i < n; ++ i)
            exist[a[i]] = true;
        for(int i = 0; i < n; ++ i)
        {
            int x = sum - a[i];
            if(exist.find(x) != exist.end())
            {
                res.push_back(a[i]);
                res.push_back(x);
                break;
            }
        }
        return res;
    }


3、两个指针逼近法
OK,有没有更神奇的办法?利用两个指针一趟就能扫描所有的组合情况?有的,但是这种方法必须基于数组是有序的情况。在对数组排序后的情况下,一个头指针i,一个尾指针j,i只能向后移动,j只能向前移动。

如果a[i]+a[j]==sum 返回相应的两个数
如果a[i]+a[j]<sum 试图使求和变大些,则i向后移动一个试试(这里不能用j++,因为j+1的情况已经处理过了,要让两个指针遍历完所有的情况,j就只能往前,i只能往后,否则情况就太乱了,放心,这样子是一定能找到满足条件的值的,因为它能遍历完所有的情况)
如果a[i]+a[j]>sum 试图使求和变小些,则j向前移动

时间复杂度O(nlogn) 空间复杂度O(1)
//两个指针两端扫描实现
    vector<int> twoSum_v3(int a[], int n, int sum)
    {
        vector<int> res;
        sort(a, a + n);
        int i = 0, j = n -1;
        while( i < j)
        {
            if(a[i] + a[j] == sum)
            {
                res.push_back(a[i]);
                res.push_back(a[j]);
                break;
            }
            else if(a[i] + a[j] < sum)
            {
                ++i;
            }
            else --j;

        }
        return res;
    }

二、若是要求我们返回下标,而不是具体数值呢?
个人觉得这时候如果数组本身有序,就利用思路三,两指针逼近法;若数组本身无序,则思路二,hasp表这时候最方便了。不可先排序后处理,这时候下标已经改变了,直接用上述方法得到的结果就不正确了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: