以另一种位图的思想来解决一道OJ题目

前言:

以前所接触到的位图的思想都是以1位的形式去存储某个数出现的次数是1次还是0次。常见的例子不外乎在《编程珠玑》上的开篇例子里,1千万个数的排序统计,用1.25M的内存空间就可以达到遍历一遍输入数据而排序好的目的。这种思想是通用的么?也就是说,假如输入数据不再是0次或者1次,而是2次或者更多的时候,如何再次用上这种思想呢?请看下面题目

题目:

输入一个数组,数组有int类型整数若干,若有其中一个是出现一次或者两次,其他数字都是出现3次,要求在时间复杂度在O(N)上限里求出那个数字。

解法一

生搬硬套位图的思想,既然最多出现3次,那么我用两个bit位来存储一个数出现的个数。那么假如输入是2千万个数的时候,所需要的空间是2.5M。20亿个数的时候,需要的是250M。显然,这种思想还是不太好,虽然符合题目要求。像这样处理海量数据肯定是要被毙掉的。可以尝试着做改进,改进思路是分批处理,如面对20亿的数据,我只自定义一个1千万数的空间,2.5M,然后每次只是处理1千万的数,如果没有出现目标数,那么再处理下一个一千万的数(按照大小区分范围)。应该也算得上一种尚可的思路。

解法二

基于位图思想的变形,我用32个数来存储所有的数中0~31位出现的个数,然后对3取余,如果是2,证明这个数的某一个位出现过2次,依次从0位推到31位。最后相或即可。

这种解法只用到了32 * 32 bit的空间,至于时间,因为需要对每个位进行统计,需要遍历输入数据32次, 32* N,可依然是符合题目的O(N)要求。

这种解法,在时间上应该是要比解法一耗时少一些。第一种解法需要遍历数据约210次,因为int类型最大值是21亿(假如不包括负数),那么就是210个1千万数了。

空间也少很多。无疑是比较好的。

    public static int singleNumber(int[] A) {
			        int[] bitNum = new int[32];
			        int values = 0;
			        boolean twiceFlag = false;
			        for(int i=0;i<32;i++){
			            for(int j=0;j<A.length;j++){
			               bitNum[i] += A[j]>>i&1;
			            }
			            values |= (bitNum[i]%3)<<i;
			            if (!twiceFlag && (bitNum[i]%3)>1) {
			            	twiceFlag = true; //如果出现两次
						}
			        }
			        if(twiceFlag)values >>= 1;
			        return values;
			    }

还有更好的解法么?欢迎网友提出交流,谢谢。O(∩_∩)O

以另一种位图的思想来解决一道OJ题目

时间: 2024-08-02 06:09:39

以另一种位图的思想来解决一道OJ题目的相关文章

位图排序思想及代码详解

输入:一个最多包含n个正整数的文件,每个数都小于n,其中n=10^7.如果在输入文件中有任何重复整数出现就是致命错误.没有其他数据与该整数相关联 输出:按升序排列的 输入整数的列表. 约束:最多有(大约)1MB的内存空间可用,有充足的磁盘存储空间可用.运行时间最多几分钟,运行时间为10秒就不需要进一步优化了.          从0开始解决这个问题的话,可以把它分为两个部分:首先随机生成K个小于N的数:再对这K个数排列.          系统参数:GCC:#pragma pack(4)    

十七、斐波那契数列 【递推思想(迭代思想)解决】

 递推思想本身并不跟函数有直接关系(虽然常常写在函数中). 其基本思路为: 为了解决一个"大"问题,根据现实逻辑,如果能够找到同类问题的一个"最小问题"的答案(通常是已知的),并且根据已知算法,又可以因此得到比最小问题"大一级"问题的答案. 而且,依次类推,又可以得到再大一级问题的答案,最终就可以得到"最大那个问题"(即要解决的问题)的答案. 可见,该思想的过程依赖与2个条件: 1,可知同类最小问题的答案: 2,大一级问题

关于数组去重的两种写法的思想!!!!!!

一般常规写法的思想,将当前项和下一项比较,如果相等,删除即可.我们来看看第一种写法吧!!function sortAry(ary){ for(var i=0;i<ary.length-1;i++){ for(var j=i+1;j<ary.length;j++){ if(ary[i]==ary[j]){ /*当前项ary[i]与后一项ary[i+1]相比较,如果相等就删除,*/ ary.splice(j,1); j--; /*注意数组塌陷,要添上j--*/ } } }}var ary=[2,1

IOS的两种框架设计思想

不管是任何一门语言,架构设计永远在其中占据着十分重要的作用,一个好的架构思想能够让程序的流程更加清晰,能够让程序工作的更加简单而有效.如果没有架构思想的话,那么所有的程序设计都将沿着一条设计思路走下去,程序设计将完全失去了活力,只剩下了千篇一律的代码编写,修改,调试:有了代码架构,我们将在程序的思想上投入更大的精力,投入更多的时间与精力去创造一些便利程序设计的结构,这将使程序的结构更加多样化,便利化,也会使你在学习工作的过程中事半功倍. 说了这么多,似乎总是没有什么有力的证据来印证这么一些话,我

几种排序算法思想

一.冒泡排序 已知一组无序数据a[1].a[2].--a[n],需将其按升序排列.首先比较a[1]与a[2]的值,若a[1]大于a[2]则交换两者的值,否则不变.再比较a[2]与a[3]的值,若a[2]大于a[3]则交换两者的值,否则不变.再比较a[3]与a[4],依此类推,最后比较a[n-1]与a[n]的值.这样处理一轮后,a[n]的值一定是这组数据中最大的.再对a[1]~a[n-1]以相同方法处理一轮,则a[n-1]的值一定是a[1]~a[n-1]中最大的.再对a[1]~a[n-2]以相同方

数学奥林匹克问题解答:一道不等式题目的三种解法

设 $a_1, a_2, \cdots, a_n\in\mathbf{N^*}$, 且各不相同. 求证: $${a_1\over1^2} + {a_2\over2^2} + \cdot + {a_n\over n^2} \ge {1\over1} + {1\over2} + \cdots + {1\over n}.$$ 解法一: 考虑使用基本不等式 $a + b\ge 2\sqrt{ab}$ 消去左边各项之分子. $$\because {a_k\over 1^2} + {1\over a_k}

PyQt种QTextEdit显示中文乱码解决

刚好碰到这个问题,当然也有的人应该不会碰到问题,可能是我胡乱修改了什么,才导致这个问题.百度搜索了一下,发现添加 QTextCodec.setCodecForTr(QTextCodec.codecForName("system")) QTextCodec.setCodecForCStrings(QTextCodec.codecForName("system")) QTextCodec.setCodecForLocale(QTextCodec.codecForName

基于Proxy思想的Android插件框架

意义 研究插件框架的意义在于下面几点: 减小安装包的体积,通过网络选择性地进行插件下发 模块化升级.减小网络流量 静默升级,用户无感知情况下进行升级 解决低版本号机型方法数超限导致无法安装的问题 代码解耦 现状 Android中关于插件框架的技术已经有过不少讨论和实现.插件通常打包成apk或者dex的形式. dex形式的插件往往提供了一些功能性的接口,这样的方式类似于java中的jar形式.仅仅是因为Android的Dalvik VM无法直接动态载入Java的Byte Code,所以须要我们提供

sgu100~199题解

老东西了..发上来吧.. Sgu题解系列  南开中学邹事成 100:A+B略 101:Domino 给n块多米诺骨牌,每张骨牌两端各有从1到6的一个数字,现在要把这些骨牌排成一列,使相邻的两块骨牌相对的面所写的数字一样. 可以把每一块多米诺骨牌想象成一条边,把面上写的数字抽象成点,比如一块骨牌正面写的1反面写的2就想象成连了一条从1到2的边,那么这就是求一条有重边的欧拉回路了,dfs一下即可. 102:Coprimes给定n求从1到n中与n互质的数的个数. 可以把n质因数分解后直接代入欧拉函数.