给定N个整数集合是否存在两个其和刚好为指定常数的元素

重新学习一遍<算法导论>,看到了这个问题:

描述一个运行时间为O(nlgn)的算法,使之能在给定一个由n个整数构成的集合S和另一个整数 X 时,判断出S中是否存在有两个其和刚好等于 X 的元素。

Solution

(1)->对整个集合进行排序,可以用快排(含有小文件策略、三者取中策略),时间复杂度O(nlogn),形成一个数组A[n]。

->设定两个下标pBegin和pEnd,分别指向数组A[n]的头尾,pBegin = 0,pEnd
= n -1。

->若(A[pBegin] +A[pEnd])==
X,找到元素对;

->若(A[pBegin]
+A[pEnd])> X,则表示所需的元素对应该要小一些,对于已经排好序的非降序数组,只需要将--pEnd即可;

->若(A[pBegin]
+A[pEnd])< X,则表示所需的元素对应该要大一些,只需要将++pBegin即可;

->直到 pBegin
 == pEnd 。总共的时间复杂度为O(nlogn+n),空间复杂度O(1)。

证明的思路:利用反证法,假如 (A[m] + A[k] )== X。初始化时,pBegin <= m,pEnd >= k。

首先证明在移动过程中pBegin 不可能大于m,假如pBegin 大于m,则在ipBegin 大于m之前,必有pBegin 必会有一次等于m,当pBegin 等于m时,pEnd 是大于k的,这时的A[pBegin]
+ A[pEnd] > X,所以pBegin 会一直停留在m处,直到pEnd 移动到k为止,所以pBegin 不会移动超过m。

同理可以证明pEnd 不会小于k,算法是正确。

(2)->对于较小的X,可以考虑利用Hash的思路,直接声明一个大小为X的数组S[X],初始化全部元素为0。消耗X个辅助空间。

->遍历一次集合,对于所有小于等于X的元素k,令S[k]++,时间复杂度n;

->遍历数组S[X],对于不为0的元素下标m(S[m]!=0),查看S[X-m]是否为0;若m == X-m,查看S[m]>=2是否为真。

->总共的时间复杂度为O(X+n),空间复杂度O(X)。但是是在X较小的情况下。

->同时这个方法可以找出所有的元素对!

拓展问题

(1)是否存在三个元素之和正好等于给定值X?

【假如 A[m]+A[k]+A[s] == X,对于所有元素i,是否在集合S(除去i)中有两个元素之和等于 X-A[i],n个元素对应n个上述的两个元素和的子问题。时间复杂度应该是O(nlogn+n^2)】不知是否有更好的思路?

(2)给定n个整数的集合S,输出集合S中所有满足 a+b=c 的整数a、b、c。

【类似1的解法,其实就是 a+b-c=0的变形】

给定N个整数集合是否存在两个其和刚好为指定常数的元素

时间: 2025-01-14 21:27:23

给定N个整数集合是否存在两个其和刚好为指定常数的元素的相关文章

A、B两个整数集合,设计一个算法求他们的交集

代码留作记录,本人水平有限,看了别人的解法真是自愧不如. 关于此题的详细探讨可以参考:http://blog.csdn.net/thebestdavid/article/details/12056293 /*A.B两个整数集合,设计一个算法求他们的交集,尽可能的高效.*/ #include <iostream> #include <cstring> #include <set> #define M 8 #define N 5 using namespace std; i

A、B两个整数集合的交集

rt,这是一个经典问题. 参考1:http://www.sysexpand.com/?path=exercises/array-intersection 参考2:http://leetcode.com/2010/03/here-is-phone-screening-question-from.html 用数组来模拟(本质上说集合中是没有重复元素的,这里用数组来模拟可以用重复元素),A.B数组长度分别为m和n.总的来说,分为以下几种方案. 方案1:两重循环判断(复杂度 O(m*n)) 暴力方法,并

C++程序设计实践指导1.5求两个整数集合并集改写要求实现

改写要求1:改写为单链表结构可以对任意长度整数集合求并集 #include <cstdlib> #include <iostream> using namespace std; struct LinkNode { int data; LinkNode* next; }; class SET { public: struct LinkNode* creat(int x[],int len); struct LinkNode* copy(LinkNode* aHead); int no

给一个整数数组,找到两个数使得他们的和等于一个给定的数 target。

描述 给一个整数数组,找到两个数使得他们的和等于一个给定的数 target. 你需要实现的函数twoSum需要返回这两个数的下标, 并且第一个下标小于第二个下标.注意这里下标的范围是 0 到 n-1. 你可以假设只有一组答案. 样例 Example1: 给出 numbers = [2, 7, 11, 15], target = 9, 返回 [0, 1]. Example2: 给出 numbers = [15, 2, 7, 11], target = 9, 返回 [1, 2]. 1 /** 2 *

Redis实现之字典跳跃表整数集合

整数集合 整数集合(insert)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现.举个栗子,如果我们创建一个只包含五个元素的集合键,并且集合中的所有元素都是整数值,那么这个集合键的底层实现就会是整数集合: 127.0.0.1:6379> SADD numbers 1 3 5 7 9 (integer) 5 127.0.0.1:6379> SMEMBERS numbers 1) "1" 2) &

Redis学习之intset整数集合源码分析

1.整数集合:整数的集合,升序排序,无重复元素 2.整数集合intset是集合键的底层实现之一,当一个集合只包含整数值的元素,并且这个集合的元素数量不多时,redis会使用整数集合作为集合键的底层实现 3.intset可通过属性自定义编码方式(int16_t/int32_t/int64_t) 4.当往inset插入新元素时,如果新元素的类型比inset的原编码类型长,那么要先对inset进行"升级"操作 5.升级操作:(不可逆操作) 1)根据新元素的类型,扩展intset底层数组的空间

redis源码学习_整数集合

redis里面的整数集合保存的都是整数,有int_16.int_32和int_64这3种类型,和C++中的set容器差不多. 同时具备如下特点: 1.set里面的数不重复,均为唯一. 2.set里面的数是从小到大有序的,这在后面的intsetAdd函数中可以看到. 然后由于我们可以同时存储int_16.int_32和int_64这3种类型,一开始只能为一种类型.假设为int_32,那么我们要插入一个int_16类型的数,只需要找到位置直接插入就可以了:但是我们要插入一个int_64类型的数,我们

学习笔记-Redis设计与实现-整数集合

整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素不多时,Redis就会使用整数集合作为集合键的底层实现. 6.1 整数集合的实现 contents数组时整数集合的底层实现:整数集合的每个元素都是contents数组的一个数组项(item),各个项在数组中按值的大小从小到大有序地排列, 并且数组中不包含任何重复项. length属性记录了整数集合包含地元素数量,也即是contents数组的长度. contents数组的真正类型取决于encoding属性

Redis 设计与实现(第六章) -- 整数集合(intset)

概述 1.intset概述 2.intset实现 3.intset升级 intset概述 整数集合是Redis集合键的底层实现之一,当值都为整数时,redis就会选择整数集合作为底层实现. 可以保存int16_t,int32_t,int64_t类型的整数值,并且集合中不会出现重复元素. intset实现 先看下intset的数据结构: typedef struct intset { uint32_t encoding; //encoding方式 uint32_t length; //长度 int