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

来源:互联网 发布:2016年网络神曲 编辑:程序博客网 时间:2024/05/15 13:30

参考: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表这时候最方便了。不可先排序后处理,这时候下标已经改变了,直接用上述方法得到的结果就不正确了。

 

0 0