寻找数组中和为定值的两个数

题目描述:输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。

下面给出这个题的不同解法(注意阐述中数列有序无序的区别):

(1)这个题目相当于,对每个a[i],查找sum-a[i]是否也在原始序列中,每一次要查找的时间都要花费为O(N),这样下来,最终找到两个数还是需要O(N^2)的复杂度(相当于用了两层for循环)。那如何提高查找判断的速度呢?答案是二分查找,可以将O(N)的查找时间提高到O(logN),这样对于N个a[i],都要花logN的时间去查找相对应的sum-a[i]是否在原始序列中,总的时间复杂度已降为O(N*logN),且空间复杂度为O(1)。(如果有序,直接二分O(N*logN),如果无序,先排序后二分,复杂度同样为O(N*logN+N*logN)=O(N*logN),空间总为O(1))。

(2)序列有序前提下:在思路1基础上还有一种更快的方法,a[i]在序列中,如果a[i]+a[k]=sum的话,那么sum-a[i](a[k])也必然在序列中,举个例子,如下:
原始序列:1、 2、 4、 7、11、15     用输入数字15减一下各个数,得到对应的序列为:
对应序列:14、13、11、8、4、 0      

要达到O(N)的复杂度(注意:这个O(n)的时间复杂度是基于原始序列有序的情况下,否则还是O(n*logn)的时间复杂度,因为排序要O(n)的时间复杂度),第一个数组以一指针i 从数组最左端开始向右扫描,第二个数组以一指针j 从数组最右端开始向左扫描,首先初始i指向元素1,j指向元素0,谁指的元素小,谁先移动,由于1(i)>0(j),所以i不动,j向左移动。然后j移动到元素4发现大于元素1,故而停止移动j,开始移动i,直到i指向4,这时,i指向的元素与j指向的元素相等,故而判断4是满足条件的第一个数;然后同时移动i,j再进行判断,直到它们到达边界。

(3)当然,还可以构造hash表,正如编程之美上的所述,给定一个数字,根据hash映射(哈希函数就是一个减式)查找另一个数字是否也在数组中,只需用O(1)的时间,这样的话,总体的算法通上述思路2 一样,也能降到O(N),但有个缺陷,就是构造hash额外增加了O(N)的空间,此点同上述思路 2。不过,空间换时间,仍不失为在时间要求较严格的情况下的一种好办法。

(4)如果数组是无序的,先排序(n*logn),然后用两个指针i,j,各自指向数组的首尾两端,令i=0,j=n-1,然后i++,j--,逐次判断a[i]+a[j]?=sum,如果某一刻a[i]+a[j]>sum,则要想办法让sum的值减小,所以此刻i不动,j--,如果某一刻a[i]+a[j]<sum,则要想办法让sum的值增大,所以此刻i++,j不动。所以,数组无序的时候,时间复杂度最终为O(n*logn+n)=O(n*logn),若原数组是有序的,则不需要事先的排序,直接O(n)搞定,且空间复杂度还是O(1),此思路是相对于上述所有思路的一种改进。(如果有序,直接两个指针两端扫描,时间O(N),如果无序,先排序后两端扫描,时间O(N*logN+N)=O(N*logN),空间始终都为O(1))。(与上述思路1相比,排序后的时间开销由之前的二分的n*logn降到了扫描的O(N))。

总结:

  • 不论原序列是有序还是无序,解决这类题有以下三种办法:
  1. 二分(若无序,先排序后二分),时间复杂度总为O(n*logn),空间复杂度为O(1);(如:思路1)
  2. 扫描一遍X-S[i]  映射到一个数组或构造hash表,时间复杂度为O(n),空间复杂度为O(n);(如:思路2和3)
  3. 两个指针两端扫描(若无序,先排序后扫描),时间复杂度最后为:有序O(n),无序O(n*logn+n)=O(n*logn),空间复杂度都为O(1)。(如:思路4)
  • 所以,要想达到时间O(N),空间O(1)的目标,除非原数组是有序的(指针扫描法),不然,当数组无序的话,就只能先排序,后指针扫描法或二分(时间n*logn,空间O(1)),或映射或hash(时间O(n),空间O(n))。时间或空间,必须牺牲一个,自个权衡吧。
  • 综上,若是数组有序的情况下,优先考虑两个指针两端扫描法,以达到最佳的时(O(N)),空(O(1))效应。否则,如果要排序的话,时间复杂度最快当然是只能达到N*logN,空间O(1)则是不在话下。

 

 

参考文章:https://blog.csdn.net/v_july_v/article/details/6419466,这篇博主是真的厉害,膜拜!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用双重循环来遍历数组中的每一对元素,判断它们的和是否等于给定的s。如果找到了一对满足条件的元素,就将它们按从小到大的顺序输出,并结束程序。如果遍历完整个数组都没有找到满足条件的元素,就输出not found。 具体实现可以参考以下代码: ```python l = [1, 2, 3, 4, 5] # 示例数组 n = len(l) # 数组长度 s = 7 # 目标和 found = False # 是否找到满足条件的元素对 for i in range(n): for j in range(i+1, n): if l[i] + l[j] == s: print(min(l[i], l[j]), max(l[i], l[j])) found = True break if found: break if not found: print("not found") ``` 输出结果为: ``` 2 5 ``` ### 回答2: 首先,可以使用双重循环遍历数组,找到所有元素对的和,如果和等于s且个元素不相等,则输出这个元素。代码如下: ``` n = len(l) found = False for i in range(n): for j in range(i+1, n): if l[i]+l[j] == s and l[i] != l[j]: found = True print(min(l[i], l[j]), max(l[i], l[j])) break if found: break if not found: print("not found") ``` 其中,`n`表示数组中元素的个数,`found`用于判断是否找到了符合要的元素对。双重循环中,第一层循环遍历所有元素的下标,第二层循环则从第一层循环后面一个下标开始,遍历所有可能的元素对。 当找到符合要的元素对后,将`found`设置为`True`,并按照从小到大的顺序输出个元素。注意,需要用`min()`和`max()`函数来保证输出的顺序正确。 如果循环结束后`found`仍为`False`,则说明没有符合要的元素对,输出`not found`即可。 ### 回答3: 解题思路: 这是一道寻找数组中和为s的个不相等元素的问题,我们可以使用哈希表的思想来解决此问题。 我们可以先遍历数组,将每个元素存入哈希表中,然后对于每个元素num,我们需要查找s - num是否在哈希表中。如果存在,则说明找到了个不相等的元素和为s,直接输出即可。如果遍历完整个数组都没有找到符合条件的数对,则输出not found。 代码实现: 下面是Python代码的实现,使用了一个字典作为哈希表来存储数组元素。时间复杂度为O(n)。 ``` def find_sum(l, s): n = len(l) d = {} for i in range(n): if s - l[i] in d: return [l[i], s - l[i]] d[l[i]] = i return "not found" l = [2, 3, 4, 5, 7, 9] s = 8 print(find_sum(l, s)) # 输出[3, 5] ``` 分析: 我们先定义了一个函数find_sum,该函数接受个参数,一个整数数组l和一个目标和s。接着,我们定义了个变量n和d,其中n表示数组l的长度,d为一个空字典。 接下来,我们利用for循环遍历数组l中的所有元素。对于当前元素l[i],我们首先判断s - l[i]是否在字典d中。如果在,说明我们已经找到了符合条件的个数,直接返回[l[i], s - l[i]]即可。如果不在,我们将当前元素及其下标i存入字典d中。 最后,如果循环结束仍未找到符合条件的数对,返回"not found"即可。 总结: 通过本题,我们学习了如何使用哈希表来解决数组中寻找个数之和的问题。哈希表可以大大提高查找的效率,使得时间复杂度从O(n^2)降为O(n)。希望同学们能够掌握哈希表的相关知识,并能够熟练地运用到实际问题中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值