先来看看这个题目:数组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. Oracle EBS-SQL (PO-9):检查期间采购订单执行情况.sql

    --采购订单执行情况查询(七天内接收情况)select pha.segment1       采购订单,         msib.segment1      物料编码,         pla.qu ...

  2. jquery.lazyload.js图片延迟加载(懒加载)--转载

    一.插件介绍 jquery.lazyload.js 是一个用 JavaScript 编写的jQuery 插件. 它可以延迟加载长页面中的图片. 在浏览器可视区域外的图片不会被载入, 直到用户将页面滚动 ...

  3. Paas

    bae sae PowerApp 还有啥???

  4. 论山寨手机与Android联姻 【8】 自己动手做XP手机

    2010年1月20日,ViewSonic在北京发布了一款真正意义的电脑手机VCP08.根据商家的宣传,VCP08之所以能够被称为真正的电脑手机,是因为“该机做到了把真正的WindowsXP操作系统嵌入 ...

  5. RoHS认证简介

    RoHS认证是<电气.电子设备中限制使用某些有害物质指令>(The restriction of the use of certain hazardous substances in el ...

  6. CC++初学者编程教程(7) 搭建Windows EclipseCCPP软件开发环境

    1根据电脑是32位还是64位来选择工具 2 查看电脑是64位 3 管理员身份运行这个文件 4 安装JDK64位 5. 下一步 6 开始安装 7 安装JAVA 8 安装进行时 9 安装成功 10解压缩 ...

  7. 解决Easyui1.3.3 IE8兼容性问题

    事先声明:项目在Firefox和Chrome上完美运行,在MSIE9.MSIE10上基本没问题,但是放在MSIE8上面运行问题就出来了.登录系统后,系统页面跳动,导致系统无法使用:我使用的是Easyu ...

  8. libiconv的静态编译

    ./configure --enable-static=yes --prefix=/usr/local/libiconv   CentOS安装transmission » Nicky Blog 安装l ...

  9. libiconv_百度百科

    libiconv_百度百科   由于历史原因,国际化的文字常常由于语言或者国家的原因使用不同的编码.目录     1libiconv历史简介     2libiconv编码简介     3libico ...

  10. Java String.replace()方法

    Java String.replace()方法用法实例教程, 返回一个新的字符串,用newChar替换此字符串中出现的所有oldChar 声明 以下是java.lang.String.replace( ...