用4KB内存寻找重复元素(算法村第十五关青铜挑战)

在海量数据中,普通的数组、链表、Hash、树等等结构无效,因为内存空间不足。而常规的递归、排序,回溯、贪心和动态规划等思想也无效,因为执行超时。这类问题该如何下手呢?这里介绍三种非常典型的思路:

1.使用位存储。

使用位存储最大的好处是占用的空间是简单存整数的1/8。例如一个40亿的整数数组,如果用整数存储需要16GB左右的空间,而如果使用位存储,就可以用0.5GB的空间,这样很多问题就能够解决了。

2.外部排序。如果文件实在太大 ,无法在内存中放下,则需要考虑将大文件分成若干小块,先处理每个块,最后再逐步得到想要的结果。这样需要遍历全部序列至少两次,是典型的用时间换空间的方法。

3.堆,如果在超大数据中找第K大、第K小,K个最大、K个最小,则特别适合使用堆来做。而且将超大数据换成流数据也可以,而且几乎是唯一的方式。口诀是"查小用大堆,查大用小堆"。

题目

给定一个数组,包含从1N的整数,N最大为32000,数组可能还有重复值,且N的取值不定。若只有4KB的内存可用,请问如何打印数组中所有重复元素。

分析

如果不限内存,我们可以创建一个大小为Nint数组,然后逐一读取数据,出现过的数据在数组中的对应位置标记为1,从而不断找到重复元素。

而在4KB的内存限制下,我们应该创建一个大小为Nbit数组。

1KB = 1024 Bytes

1 Byte = 8 bits

4KB = 4 * 1024 * 8 bits = 32768 bits。

比特的单位是 bit,但通常表达多个比特时使用复数形式 bits

例如,当我们说"4KB等于32768 bits"时,就是在用bits来表示比特的总数。

因此4KB足够我们创建32000比特大小的比特数组,其中一个比特位置就代表一个整数。例如...10000100表示数据中3和8出现过,再碰到重复的3、8,就输出一下。

演示代码

代码仅供参考,面试时能讲清楚解题逻辑就行,不用写代码

java 复制代码
public class FindDuplicatesIn32000
{
    //比特集以及相关操作
    class BitSet
    {
		int[] bits;
        
        //创建大小为size的比特数组
		public BitSet(int size)
        {
			this.bibit = new int[size >> 5];	//除以32
		}
        
        //判断某个位置的数是否出现过,出现过返回true,否则返回false
		boolean get(int pos)
        {
            int posBit = (pos >> 5);	//除以32
            int bitNumber = (pos & 0x1F); // ?
            //取模32。该操作会保留 pos 的最低5位,而将高于第五位的所有位设置为0。例如,若 pos 的值为 0b11011011(十进制的 219),那么 pos & 0x1F 的结果将是 0b00011011(十进制的 27)
            return (bits[posBit] & (1 << bitNumber)) != 0;	// ?
        }
        
        //将比特数组的pos位置设置为1
	    void set(int pos)
        {
			int posBit = (pos >> 5);	//除以32
			int bitNumber = (pos & 0x1F);// ?	//取模32
			bits[posBit] = bits[posBit] | (1 << bitNumber);// ?
		}
    }
    
	public void checkDuplicates(int[]array)
    {
		BitSet bits = new BitSet(32000);
        
		for (int i = 0; i < array.length; i++)
        {
			int num = array[i];  //num的范围是[1,N]
			int pos = num - 1;	//num在比特数组中的位置(数组下标从0开始)
            
			if (bits.get(pos))	//出现重复元素
				System.out.println(num);
			else	//元素第一次出现
				bits.set(pos);	//标记一下
        }
    }
}
相关推荐
rabbit_pro6 分钟前
Java使用Mybatis-Plus封装动态数据源工具类
java·python·mybatis
期待のcode12 分钟前
Java虚拟机类加载机制
java·开发语言
瀚高PG实验室13 分钟前
逻辑导入导出(pg_dump/pg_restore)用法2-导入到不同的schema或tablespace
数据库·瀚高数据库
whyfail18 分钟前
前端数据存储新选择:IndexedDB与Dexie.js技术指南
前端·javascript·数据库
短剑重铸之日20 分钟前
《SpringBoot4.0初识》第四篇:原生镜像
java·原生镜像·springboot4.0
煎蛋学姐21 分钟前
SSM校园快递系统q9061(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·开题报告·java 开发·校园信息化·ssm 框架
程序员欣宸23 分钟前
LangChain4j实战之十二:结构化输出之三,json模式
java·人工智能·ai·json·langchain4j
元亓亓亓32 分钟前
考研408--操作系统--day11--文件管理&逻辑物理结构&目录&存储空间管理
数据库·考研·文件管理·408
天若有情67340 分钟前
打破思维定式!C++参数设计新范式:让结构体替代传统参数列表
java·开发语言·c++
初晴や42 分钟前
【C++】图论:基础理论与实际应用深入解析
c++·算法·图论