42亿QQ,O(1)时间复杂度完成查找

一、问题描述:

  1.在42亿个qq号码中,如何使用O(1)时间复杂度去查找一个QQ号是否存在。

  2.qq号的位数小于13位,存储着42亿QQ号的内存不得超过600MB.

二、位图排序思想

  由于待排序的数据记录较多,我们单纯地使用常见的排序方法时间效率较低,运行时间会很长。而且内存空间有限(限制为1MB左右),所以我们不能同时把所有整数读入内存(如果每个整数使用7个字节来存储,那么1MB内存空间只能存大约143000个数字)。当然我们可以多次读取输入文件,多次排序,但是更好的方案是使用位图排序,可以使用有限的1MB内存空间并只进行一趟排序。

      1.根据待排序集合中最大的数,开辟一个位数组,用来表示待排序集合中的整数;

      2.待排序集合中的数字在位数组中的对应位置置1,其他的置0;

      例如,待排序集合{1,2,3,5,8,13}可以表示为:0-1-1-1-0-1-0-0-1-0-0-0-0-1

      这样排序过程自然可以分为三步:

      第一步:将所有的位都置为0;

      第二步:通过读入文件中的每个整数,将每个对应的位都置为1;

      第三步:检验每一位,如果该位为1,输出对应的整数。

      注意:位图排序是使用一个二进制位而不是一个整数来表示0或1,这样可以大大地减少所需要的内存空间。使用位图排序的前提是要知道待排序序列中的最大数。位图排序的缺点是有些数没有出现过,仍要为其保留一个位。故位图排序比较适合关键字密集的序列,例如一个QQ号码。

/*Phase 1: initialize set to empty*/

  for
i = [0, n)

    bit[i] = 0

/*Phase 2: insert present elements into the set*/

  for
each i in the input file

    bit[i] = 1

/*Phase 3: write sorted output*/

  for
i = [0, n)

    if
bit[i] == 1

      write i on the output file

三、使用位图排序的方法

      位图排序时,我们需要考虑:给出一个数,如何找到其对应位图的位置,方法就是首先找到该数对应的字节,然后在找到该数对应的位。例如一个QQ号是:983262245,则将bit的98326625位进行标记。bitset是C++提供的一种位集合的数据结构,它让我们可以像使用数组一样使用位,可以访问指定下标的bit位。因此将通过bitset容器进行存储42个qq号码。由于一个字节可以存放8个QQ号码,则4200000000/8/1014/1024 = 500.679Mb,内存合适,通过bit位下表来判断QQ号码是否存在。

#include<iostream>
#include<bitset>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const unsigned int MAX = 4200000010;
typedef unsigned int UT;
bitset<MAX> bit;
int main(){
	//开始存储QQ
	for(UT i=1;i<10;i++){
		UT qq;
		printf("请输入第%d个QQ号:",i);
		scanf("%d",&qq); 
		bit.set(qq);
	} 
	UT qq;
	printf("请输入:");
	while(scanf("%d",&qq)!=0){
			
		if(bit.test(qq)){
			printf("Yes\n");
		}
		printf("请输入:");
	}
	return 0;
} 

存储:空间占用大约500Mb

查找:时间复杂度为O(1)

通过位排序的方法,在实现内存内,实现在O(1)时间复杂度内进行一个QQ号码的查找。



### 时间复杂度的概念与计算方法 时间复杂度是衡量算法效率的重要指标,用于描述算法运行时间与输入规模之间的关系。它通过分析算法中基本操作的执行次数来评估算法的性能。 #### 基本概念 时间复杂度通常用大O符表示,反映算法在最坏情况下的运行时间增长趋势。例如,对于一个输入规模为 \( n \) 的问题,如果算法的基本操作执行次数与 \( n \) 成正比,则其时间复杂度为 \( O(n) \)[^2]。 #### 计算方法 时间复杂度的计算主要基于以下步骤: 1. 确定算法中的基本操作(如加法、比较、赋值等)。 2. 分析基本操作的执行次数如何随输入规模变化。 3. 忽略低阶项和常数因子,保留最高阶项作为时间复杂度。 #### 示例分析 ##### 示例 1:常数时间复杂度 \( O(1) \) ```python def constant_time_example(): return 42 ``` 上述函数无论输入如何,仅执行一次返回操作,因此时间复杂度为 \( O(1) \)[^4]。 ##### 示例 2:线性时间复杂度 \( O(n) \) ```python def linear_time_example(arr): total = 0 for num in arr: total += num return total ``` 该函数遍历数组 `arr` 中的所有元素,执行次数与数组长度 \( n \) 相同,因此时间复杂度为 \( O(n) \)[^3]。 ##### 示例 3:平方时间复杂度 \( O(n^2) \) ```python def quadratic_time_example(arr): count = 0 for i in range(len(arr)): for j in range(len(arr)): count += 1 return count ``` 此函数包含两层嵌套循环,内层循环每次迭代都会执行 \( n \) 次,总执行次数为 \( n \times n = n^2 \),故时间复杂度为 \( O(n^2) \)[^2]。 ##### 示例 4:对数时间复杂度 \( O(\log n) \) ```python def logarithmic_time_example(n): steps = 0 while n > 1: n = n // 2 steps += 1 return steps ``` 每次循环将 \( n \) 减半,直到 \( n \leq 1 \)。循环次数为 \( \log_2 n \),因此时间复杂度为 \( O(\log n) \)[^4]。 ##### 示例 5:线性对数时间复杂度 \( O(n \log n) \) ```python def linear_logarithmic_time_example(arr): result = [] for num in arr: temp = num while temp > 1: temp = temp // 2 result.append(temp) return len(result) ``` 外层循环遍历数组 \( n \) 次,内层循环执行 \( \log n \) 次,总执行次数为 \( n \times \log n \),故时间复杂度为 \( O(n \log n) \)[^4]。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值