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 ...
随机推荐
- SQL Server 中@@IDENTITY的用法
原文地址:http://www.studyofnet.com/news/145.html 本文导读:@@IDENTITY是返回上次插入的标识值,标识值一般指的是自动增长值.但是如果想只返回插入到当前作 ...
- Ajax学习教程在线阅读
1.什么是AJAX ?(1) 2.什么是AJAX ?(2) 3.什么是AJAX ?(3) 4.什么是AJAX ?(4) 5.Ajax基础教程(1)-Ajax简介 1.1 Web应用简史 6.Aja ...
- Win7下unetbootin-windows-585工具制作Ubuntu12.04 U盘启动盘
1.下载unetbootin-windows-585工具,网址如下: unetbootin-windows-585 2.unetbootin-windows-585制作U盘启动盘 准备好1个4G的U盘 ...
- Floodlight中 处理packetin消息的顺序(1)
当Controller和SW建立连接之后,就能够处理来自SW的各种OF msg.当接收到 packetin 消息之后,会将其分发给各个监听了这个OFMessage的listeners,所以假设我们要设 ...
- Coroutine,你究竟干了什么?
一 引子 使用Unity已经有一段时间了,对于Component.GameObject之类的概念也算是有所了解,而脚本方面从一开始就选定了C#,目前来看还是挺明智的:Boo太小众,而且支持有限:JS( ...
- windows编程之菜单操作
分清几个概念 <1>"主菜单" 和 "顶层菜单" 是一个意思. <2>主菜单中的项目叫做 "弹出菜单" 或者 &qu ...
- 清空DateTimePicker控件的好方法
[控件ID,不要加这个方括号].Format = DateTimePickerFormat.Custom; [控件ID,不要加这个方括号].CustomFormat = " "; ...
- org.jawin.COMException: 8000ffff: Invalid ptr null flag(原址:http://osdir.com/ml/windows.devel.jawin/2006-01/msg00013.html)
I now realise my arguments to invoke should be more along the lines of byte[] result = tApp.invoke(& ...
- Python核心编程读笔 3
第四章 Python对象 一.python对象的三个特性: 身份:可用id()函数查看,可以被认为是该对象的内存地址 类型:可用type()函数查看 值 二.标准类型 数字 整型 布尔 长整型 浮点型 ...
- centos之tomcat安装
1.环境说明 系统:centos, 2.6.32-573.el6.x86_64; tomcat: apache-tomcat-7.0.68 2.下载文件并上传 下载apache-tom ...