bit-map牛刀小试:数组test[X]的值全部在区间[1, 8000]中, 现要输出test中重复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB
2015-06-22 18:45
525 查看
先来看看这个题目:数组test[X]的值全部在区间[1, 8000]中, 现要输出test中重复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB.
好, 我们先给出一个不限空间的解法(为了程序方便, 假设X为10, 实际上可能很大):
结果为:
2
5
显然, 上述程序在空间上超标(且当X<N=8000时, 时间超标), 究其原因是: 让一个int去存一个二值状态, 太浪费空间了, 和不用一个bit来存呢? 所以, 我们自然想到了用bit-map来操作, 如下:
2
5
且满足题目要求。 但是, 我随后发现这个程序还有个问题: 当test数组中某元素出现次数大于2时, 会重复输出, 比如:
2
2
5
我想了一下, 暂时没有想到只打印2, 5且符合题意的方法。 如果大家有好的思路, 欢迎赐教
好, 我们先给出一个不限空间的解法(为了程序方便, 假设X为10, 实际上可能很大):
#include <iostream> using namespace std; #define X 10 #define N 8000 // 输出重复的数字 void printDup(const int test[], int n) { int a = {0}; int i = 0; for(i = 0; i < n; i++) { a[test[i] - 1]++; } for(i = 0; i < N; i++) // 注意, 此处是N而不是n { if(a[i] > 1) { cout << i + 1 << endl; } } } int main(void) { int test[X] = {1, 2, 3, 4, 2, 5, 6, 7, 5, N}; printDup(test, X); return 0; }
结果为:
2
5
显然, 上述程序在空间上超标(且当X<N=8000时, 时间超标), 究其原因是: 让一个int去存一个二值状态, 太浪费空间了, 和不用一个bit来存呢? 所以, 我们自然想到了用bit-map来操作, 如下:
#include <iostream> using namespace std; #define X 10 #define BIT_INT 32 // 1个int可以标志32个坑 #define SHIFT 5 #define MASK 0x1f #define N 8000 int a[1 + N / BIT_INT]; // 需要1 + N / BIT_INT 个整数来标志N个事物 // 将所有位都初始化为0状态 void setAllZero() { memset(a, 0, (1 + N / BIT_INT) * sizeof(int)); } // 设置第i位为1 void setOne(int i) { a[i >> SHIFT] |= (1 << (i & MASK)); } // 设置第i位为1 void setZero(int i) { a[i >> SHIFT] &= ~(1 << (i & MASK)); } // 检查第i位的值 int getState(int i) { return (a[i >> SHIFT] & (1 << (i & MASK))) && 1; } // 输出重复的数字 void printDup(const int test[], int n) { int i = 0; for(i = 0; i < n; i++) { int state = getState(test[i] - 1); if(0 == state) { setOne(test[i] - 1); } else { cout << test[i] << endl; } } } int main(void) { setAllZero(); int test[X] = {1, 2, 3, 4, 2, 5, 6, 7, 5, N}; printDup(test, X); return 0; }结果为:
2
5
且满足题目要求。 但是, 我随后发现这个程序还有个问题: 当test数组中某元素出现次数大于2时, 会重复输出, 比如:
#include <iostream> using namespace std; #define X 10 #define BIT_INT 32 // 1个int可以标志32个坑 #define SHIFT 5 #define MASK 0x1f #define N 8000 int a[1 + N / BIT_INT]; // 需要1 + N / BIT_INT 个整数来标志N个事物 // 将所有位都初始化为0状态 void setAllZero() { memset(a, 0, (1 + N / BIT_INT) * sizeof(int)); } // 设置第i位为1 void setOne(int i) { a[i >> SHIFT] |= (1 << (i & MASK)); } // 设置第i位为1 void setZero(int i) { a[i >> SHIFT] &= ~(1 << (i & MASK)); } // 检查第i位的值 int getState(int i) { return (a[i >> SHIFT] & (1 << (i & MASK))) && 1; } // 输出重复的数字 void printDup(const int test[], int n) { int i = 0; for(i = 0; i < n; i++) { int state = getState(test[i] - 1); if(0 == state) { setOne(test[i] - 1); } else { cout << test[i] << endl; } } } int main(void) { setAllZero(); int test[X] = {1, 2, 3, 4, 2, 5, 6, 2, 5, N}; // 2出现3次 printDup(test, X); return 0; }结果为:
2
2
5
我想了一下, 暂时没有想到只打印2, 5且符合题意的方法。 如果大家有好的思路, 欢迎赐教
相关文章推荐
- 开发板与PC机的连接过程(包括NFS服务器的配置)
- Android 友盟社会化组件-分享实现
- MVC返回图片
- ReactJS -- 初学入门
- BZOJ3103 : Palindromic Equivalence
- 第五题
- 深入理解Java中的HashMap的实现原理
- Unable to load configuration. - bean - jar:file:/E:/tomcat/lib/struts...
- 用nohup命令让Linux下程序永远在后台执行
- jquery easyui常见问题:
- 6
- 再论 new 对象 时 jvm 的工作步骤
- H264 编解码器架构简单
- groovy : 正则表达式
- linux sun/awt/X11GraphicsEnvironment
- 第三题
- MVC框架简述
- 读取文件或超大文件的几种方式
- 表关系:一对一的两种方式
- JAVA字符串格式化-String.format()使用