• 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且符合题意的方法。 假设大家有好的思路, 欢迎赐教奋斗





     

  • 相关阅读:
    4.2编写第一个servlet(500错误解决)超级开心
    springmvc文件上传下载
    找出字符串中不重复字符的最长子串的长度
    微信小程序接入,https服务器搭建和调试
    js常用写法
    通过条件删除标签
    xml的修改遍历,以及建立
    shelve模块
    dump与load
    locate,find,df,mount,du命令
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/5204427.html
Copyright © 2020-2023  润新知