首页 > 编程语言 >算法练习:两数之和

算法练习:两数之和

时间:2022-12-07 16:01:57浏览次数:51  
标签:数组 int 复杂度 练习 nCount 算法 哈希 两数 nArray


题目:给定一个整型数组,是否能找出两个数使其和为指定的某个值?注:整型数组中不存在相同的数。

一、解题方法

1、暴力解法(时间复杂度O(n^2) )

这是最容易想到的一种方法,即使用两层循环,从数组里取出一个数,然后在此数之后部分找出另外一个数,计算两数之和,判断是否等于指定值。如下:

//直观的办法,使用两个循环
bool IsExistSumOfTwoNum( int nArray[], int nCount, int nSum )
{
bool bRet = false;
for ( int i = 0; i < nCount - 1; ++i )
{
for ( int j = i + 1; j < nCount; ++j )
{
if ( ( nArray[i] + nArray[j] ) == nSum )
{
bRet = true;
break;
}
}
}

return bRet;
}


此种方法的的时间复杂度为O(n^2),那么能否降低此复杂度呢?答案是可以的,请看第二种方法。

 

2、排序加首尾指针(时间复杂度O(nlogn) )

先对数组进行从小到大的排序,然后设置首尾指针,从首尾两端开始移动,一次移动一端的指针,直至两指针相遇或者两指针指向的数的和为指定的值。

假设两指针为i,j,其中i < j,如果a[i]、a[j]之和大于指定值,那么要找的两个数一定在j的左侧,如果a[i]、a[j]之和小于指定值,那么要找的两个数一定在i的右侧。可用反证法证明此结论的正确性,证明略。

bool IsExistSumOfTwoNum( int nArray[], int nCount, int nSum )
{
//从小到大排序
std::sort( nArray, nArray+nCount, std::less<int>() );

//首尾指示
int i = 0;
int j = nCount - 1;

bool bRet = false;
while( i < j )
{
if ( ( nArray[i] + nArray[j] ) == nSum )
{
bRet = true;
break;
}
else if ( ( nArray[i] + nArray[j] ) > nSum )
{
--j;
}
else
{
++i;
}
}

return bRet;
}


此种算法中,一开始有一个排序,最好的排序的时间复杂度可为O(nlogn),比如堆排序、归并排序、快速排序。While循环至多扫描一遍数组,所以其时间表复杂度为O(n)。由此可得,最终的时间复杂度为O(nlogn)。那么能否再降低时间复杂度呢?答案还是可以的,但是这时需要一个额外的存储空间,请看第三种方法。

 

3、利用哈希表(时间复杂度O(n) )

将复杂度为O(nlogn)降低至O(n),首先想到的是哈希表,因为哈希表的查找时间复杂度为O(n)。

扫描一遍数组,将其数组各个值保存至哈希表中,比如键值:<数组值--索引>。然后再次开始从头扫描数组,检查指定值与当前值的差值是否在哈希表中(特殊情况:如果遇到差值为当前值时,那么不应返回,因为数组中的值是不相同的)。

程序代码实现说明:程序中使用c++标准库中的set代替哈希表,因为标准库中还未收录哈希表相关部分。此处若需要两数的索引信息,可以考虑使用map。因为set、map内部使用的是红黑树数据结构,查找效率高,具体的复杂度,我还没好好研究,呵呵。希望此处用set代替哈希表,不要引起误会,姑且将它理解为查找复杂度为常数时间的东西吧。

 

//使用额外的存储空间
bool IsExistSumOfTwoNum( int nArray[], int nCount, int nSum )
{
//打描一遍数组,将值存放于哈希表中
//(注:此处使用set代替下哈希表,它内部实现说是红黑树,还没仔细研究过,呵)
std::set<int> siSetTemp;
int i = 0;
bool bRet = false;
for ( i = 0; i < nCount; ++i )
{
siSetTemp.insert( nArray[i] );
}

for ( i = 0; i < nCount; ++i )
{
std::set<int>::iterator it = siSetTemp.find( nSum - nArray[i] );
if ( it != siSetTemp.end() && (nSum != 2 * nArray[i] ) )
{
bRet = true;
break;
}
}

return bRet;

}


此种算法中,哈希表的查找是常数时间,所以时间复杂度为O(n),空间复杂度为

O(n),即数组大小O(n)。

 

二、扩展问题

如果要返回其中所有的可能或者数组里面存在相同的数,那么应当怎么解决呢?相信有了以上的知识,这个解决起来也不难。一个是开辟一个保存结果的数组,搜索完整个数组空间;另外一个无非就是让哈希表中多存放点数据。



系列文章说明:
1.本系列文章[算法练习],仅仅是本人学习过程的一个记录以及自我激励,没有什么说教的意思。如果能给读者带来些许知识及感悟,那是我的荣幸。
2.本系列文章是本人学习陈东锋老师《进军硅谷,程序员面试揭秘》一书而写的一些心得体会,文章大多数观点均来自此书,特此说明!
3.文章之中,难免有诸多的错误与不足,欢迎读者批评指正,谢谢.


作者:山丘儿


标签:数组,int,复杂度,练习,nCount,算法,哈希,两数,nArray
From: https://blog.51cto.com/u_15905375/5919632

相关文章

  • 操作系统:银行家算法(避免死锁)
    算法介绍:程序实现:/*****************************************************程序:银行家算法实现作者:小单时间:2013年11月5日***************************......
  • 水仙花束的练习题
    packagewxy1;publicclassw{ publicstaticvoidmain(Stringargs[]){ //水仙花束的练习 for(inti=100;i<1000;i++){ intb=i/100; intc=i/......
  • KMP算法详解-字符串匹配
    1.什么是KMP是由这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP2.KMP的用处KMP主要用于字符串匹配。KMP的主要思想是当出现字符串不匹......
  • GUI-6-练习代码组合框及按钮-2022-12-7
    packagecom.lr.guifirstdemo;importjava.awt.*;importjava.awt.event.WindowAdapter;importjava.awt.event.WindowEvent;publicclasstestDemo05{publicstatic......
  • 算法练习:两指针之有序数组去重
    问题描述给出一个有序数组,就地移除重复元素,保持每个元素只出现一次,并返回新数组的长度。 问题分析这个比较简单,直接使用两个指针,一个在前,一个在后,扫描一遍数组即可。时间复......
  • 算法练习:两指针之三色排序
    问题描述输入一个整型数组,每个元素在0~2之间,其中0,1,2分别代表红、白、蓝。现要求对数组进行排序,相同颜色的在一起,而且按红白蓝顺序先后排列。要求时间复杂度为O(n)。 问题分......
  • 五. 排序算法
    1.定义:1.1原地排序和非原地排序def.原地排序算法使用恒定的的额外空间来产生输出。原地排序:选择排序,插入排序,希尔排序,快速排序,堆排序。非原地排序:归并排序,计数排序,基数排......
  • 一致性哈希算法详解
    一致性哈希是什么,使用场景,解决了什么问题?转载:https://mp.weixin.qq.com/s/hJHMlbQpANwMjx9BetwkUg 1.如何分配请求大多数网站背后肯定不是只有一台服务器提供服务,因......
  • 数据挖掘算法-KNN算法
    ✅作者简介:热爱科研的算法开发者,Python、Matlab项目可交流、沟通、学习。......
  • 机器学习--Kmeans聚类算法
    1.1概述K-means算法是集简单和经典于一身的基于距离的聚类算法采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为类簇是由距离靠近的对象......