先来看看这个题目:数组test[X]的值所有在区间[1, 8000]中。 现要输出test中反复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB.

好, 我们先给出一个不限空间的解法(为了程序方便, 如果X为10, 实际上可能非常大):

#include <iostream>
using namespace std; #define X 10
#define N 8000 // 输出反复的数字
void printDup(const int test[], int n)
{
int a[N] = {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且符合题意的方法。 假设大家有好的思路, 欢迎赐教

bit-map牛刀小试:数组test[X]的值所有在区间[1, 8000]中, 现要输出test中反复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB的更多相关文章

  1. JavaScript Array返回值以及是否改变原数组。

    1.        push:最后一位新增://改变原数组         arr.push("123");         返回值是数组的长度:         var b =  ...

  2. JS 数组的常用方法归纳之不改变原数组和其他

    不改变原数组的方法 concat() 连接两个或多个数组,不改变现有数组,返回新数组,添加的是数组中的元素 join(",") 把数组中的所有元素放入一个字符串,通过‘,’分隔符进 ...

  3. js数组方法 改变原数组和不改变原数组的方法整理

    改变原数组: pop():   删除 arrayObject 的最后一个元素,把数组长度减 1,并且返回它删除的元素的值.如果数组已经为空,则 pop() 不 改变数组,并返回 undefined 值 ...

  4. js操作改变原数组的解决方法

    最近在开发的时候发现js中的循环操作会改变原数组,var一个变量承接也不行 甚至连map方法都会改变原数组,下面是解决方法 let a = ['a','b','c'] let b = [[2, 0, ...

  5. Java方法调用数组,是否改变原数组元素的总结

    Java方法调用数组,是否改变原数组元素的总结 //个人理解, 欢迎吐槽 注意String是引用型变量, 我的理解也就是指向型, 指向一个数据或变量, 画图理解最容易, string 指向的 数据的值 ...

  6. JS在不改变原数组的情况下复制一个新的数组

    var a={1,2,3,4} var data= JSON.parse(JSON.stringify(a[0])) a.push(data) a[4]=5 这样就不会改变原数组a的数据

  7. JS 数组的常用方法详解归纳之改变原数组方法

    shift() 把数组的第一个元素从其中删除,并返回第一个元素的值, 如果数组是空的,那么 shift() 方法将不进行任何操作,返回 undefined 值.请注意,该方法不创建新数组,而是直接修改 ...

  8. 合并数组,改变原数组apply与不改变原数组

    一看见合并数组,可能第一反应就是concat,concat确实具有我们想要的行为,但它实际上并不附加到现有数组,而是创建并返回一个新数组. 同样你也许会想到ES6的扩展运算符...         但 ...

  9. 解决reverse改变原数组

    let arr =[1,2,3,4] console.log(arr) //[1,2,3,4] let arr2 = arr; console.log(arr2) //[4,3,2,1] consol ...

随机推荐

  1. perl 公交车查询

    <pre name="code" class="cpp">decode_json 必须是unicode形式的字符,Dump不支持显示unicode形 ...

  2. CC++初学者编程教程(11) 配置Windows数据库服务器

    1.我们新建一个虚拟机. 2. 选择默认的WorkStation10.0. 3.我们选择VS2012的镜像. 4.我们设置用户密码,跳过WindowsSever2012密钥 5.我们选择是,稍后手动激 ...

  3. Codeforces 325D

    #include <cstdio> #include <algorithm> #include <cstring> #include <cstdlib> ...

  4. 04737_C++程序设计_第4章_类和对象

    例4.1 描述点的Point类. 例4.2 根据上面对Point类的定义,演示使用Point类的对象. #define _SCL_SECURE_NO_WARNINGS #include <ios ...

  5. ACCESS 里面的坑

    在vs2005中用sql语句访问access数据库出现replace函数未定义错误,后来查询得知,在不能用replace访问access. 问题:   1.为什么以前运行正常的Access数据库,搬到 ...

  6. wcf系列学习5天速成——第五天 服务托管

    今天是系列的终结篇,当然要分享一下wcf的托管方面的知识. wcf中托管服务一般有一下四种: Console寄宿:             利于开发调试,但不是生产环境中的最佳实践. winform寄 ...

  7. rem vh vw vmin vmax ex ch

    rem 我们首先介绍下和我们熟悉的很相似的货.em 被定义为相对于当前对象内文本的字体大小.如果你给body小哥设置了font-size字体大小,那么body小哥的任何子元素的1em就是等于body设 ...

  8. getchar()用法

    getchar() .从缓冲区读走一个字符,相当于清除缓冲区 .前面的scanf()在读取输入时会在缓冲区中留下一个字符'\n'(输入完s[i]的值后按回车键所致),所以如果不在此加一个getchar ...

  9. RapidMiner的基本使用(一个医疗数据的简单决策树算法分析)

    RapidMiner的基本使用(一个医疗数据的简单决策树算法分析) RapidMiner的基本使用(一个医疗数据的简单决策树算法分析) 需要分析的文件: 右键分别创建读取excel数据,选择属性,设置 ...

  10. windows7 64位下运行 regsvr32 注册ocx或者dll的方法

    来源:转载   it won't work for you unless you have some form of Visual Basic tools loaded on your system: ...