bit-map牛刀小试:数组test[X]的值所有在区间[1, 8000]中, 现要输出test中反复的数。要求:1. 不能改变原数组; 2.时间复杂度为O(X);3.除test外空间不超过1KB
先来看看这个题目:数组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的更多相关文章
- JavaScript Array返回值以及是否改变原数组。
1. push:最后一位新增://改变原数组 arr.push("123"); 返回值是数组的长度: var b = ...
- JS 数组的常用方法归纳之不改变原数组和其他
不改变原数组的方法 concat() 连接两个或多个数组,不改变现有数组,返回新数组,添加的是数组中的元素 join(",") 把数组中的所有元素放入一个字符串,通过‘,’分隔符进 ...
- js数组方法 改变原数组和不改变原数组的方法整理
改变原数组: pop(): 删除 arrayObject 的最后一个元素,把数组长度减 1,并且返回它删除的元素的值.如果数组已经为空,则 pop() 不 改变数组,并返回 undefined 值 ...
- js操作改变原数组的解决方法
最近在开发的时候发现js中的循环操作会改变原数组,var一个变量承接也不行 甚至连map方法都会改变原数组,下面是解决方法 let a = ['a','b','c'] let b = [[2, 0, ...
- Java方法调用数组,是否改变原数组元素的总结
Java方法调用数组,是否改变原数组元素的总结 //个人理解, 欢迎吐槽 注意String是引用型变量, 我的理解也就是指向型, 指向一个数据或变量, 画图理解最容易, string 指向的 数据的值 ...
- JS在不改变原数组的情况下复制一个新的数组
var a={1,2,3,4} var data= JSON.parse(JSON.stringify(a[0])) a.push(data) a[4]=5 这样就不会改变原数组a的数据
- JS 数组的常用方法详解归纳之改变原数组方法
shift() 把数组的第一个元素从其中删除,并返回第一个元素的值, 如果数组是空的,那么 shift() 方法将不进行任何操作,返回 undefined 值.请注意,该方法不创建新数组,而是直接修改 ...
- 合并数组,改变原数组apply与不改变原数组
一看见合并数组,可能第一反应就是concat,concat确实具有我们想要的行为,但它实际上并不附加到现有数组,而是创建并返回一个新数组. 同样你也许会想到ES6的扩展运算符... 但 ...
- 解决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 ...
随机推荐
- 在 Linux ubuntu 上安装 *.sh 文件
简单说来就两步: 增加可执行权限 执行 事情是这样的,打算在 ubuntu 上安装一个 NetBeans IDE 来学习 Java,但是下载下来的文件是 .sh 格式的.图形界面下右键没有执行的选项. ...
- mysql-bin.000001文件的来源及处理方法
用ports安装了mysql以后,过一段时间发现/var空间不足了,查一下,会发现是mysql-bin.000001.mysql-bin.000002等文件占用了空间,那么这些文件是干吗的?这是数据库 ...
- hdu 1078(记忆化搜索)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1078 //dp[i][j]表示从点i,j处开始能获得的最多cheese #include <io ...
- vim简单命令教程-firstblood
你想以最快的速度学习人类史上最好的文本编辑器VIM吗?你先得懂得如何在VIM幸存下来,然后一点一点地学习各种戏法. Vim the Six Billion Dollar editor Better, ...
- C# base和this[转]
new关键字引起了大家的不少关注,尤其感谢Anders Liu的补充,让我感觉博客园赋予的交流平台真的无所不在.所以,我们就有必要继续这个话题,把我认为最值得关注的关键字开展下去,本文的重点是访问关键 ...
- Android编程之LayoutInflater的inflate方法具体解释
LayoutInflater的inflate方法,在fragment的onCreateView方法中经经常使用到: public View onCreateView(LayoutInflater in ...
- node.js(五)字符串转换
1.stringify函数的基本用法 stringify函数的作用就是序列化对象,也就是说将对象类型转换成一个字符串类型(默认的分割符("&")和分配符("=&q ...
- AngularJS学习资源
图灵社区 : 图书 : AngularJS入门教程 http://www.ituring.com.cn/book/1206 AngularJS 教程 | 菜鸟教程 http://www.runoob. ...
- win7 64位系统调试zkemkeeper.dll出错误解决
最近调用中控科技dll文件总是会出现上问题,网上找了大半天都没解决? 今天终于解决,原来是旧的dll文件是有问题,在中控网站上下载了最新的sdk(64位),解压,找到sdk的全部文件夹. 全选所有的: ...
- Linux学习之more命令
more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会 ...