在一个正数数组A[]中,看是否存在两个数,要求这两个数之和等于某个指定的数S。
当然,解法有很多种。
我就把我想到的,以及别人提供的一些思路总结一下。反正大概都是头脑风暴了。
1. 最朴实的做法
两重for循环。就算只算一个矩阵的下三角,那也是O(n^2)的量级。
2. 排序以后再找
因为是数组中全是正数,把S分解成两个整数相加,最大也就是S-1了。所以,如果能将数组A[]是个有序数组,就能很快将搜索范围缩小。于是我想了以下办法。
(1) 基数排序。O(dn)。d是关键字的位数。.e.g. 127的位数是3。
(2) 排序以后,二分查找到S的位置M。搜索范围降到了A[0] - A[M-1]。log2(n)。
(3) 再用第1种方法,O(M^2)。
3. 借助set
如果不排序,从左往右扫描A[],用set。
(1) i=0。遇到第一个数A[i],就把S-A[i]放入set。i++。
(2) 遇到第二个数A[i],就去看set中是否有A[i]。若有,就结束;若没有,就把S-A[i]继续放入set。i继续++。
(3) 重复上述过程。
据说STL的set是用红黑树实现的,查找、插入、删除等操作的时间复杂度为O(log2n)。
那么,这样做的复杂度,会是多少呢?
4. 那hashmap呢?
据说STL的map也是用红黑树实现的。hashmap是用哈希表实现的。
那么C++的hashmap怎么写?各种操作的复杂度大概是多少呢?
map和hashmap的区别呢?如果有碰撞,冲突怎么解决呢?所需时间呢?
5. 找到S的位置,把小于S的都放在S的左边
这个做法就类似于“如何从N个乱序数据中,快速地找出第K小的数?”了。
Review:快速找出第K小的数
先累计比S小的一共有多少个数,假设是M个,然后通过快排的找法,很快就能把范围缩小至M个了。