(bitmap)给定一个字符串数组,从中找出第一个只出现一次的字母

来源:互联网 发布:轰炸机软件免费版 编辑:程序博客网 时间:2024/04/29 22:14

来源:山三五岳合创:http://www.tnove.com/?p=170

今天针对该问题看有什么可以优化的地方: 首先看看网上一个同学的解法:

利用哈希表,因为字符最多只有255个,可以 利用这个特性建立一个哈希表,将字符串中所有的字符映射到 这个哈希表中,记录出现的每个字符的个数。最后查找哈希表 获取第一个出现字数为一的字母。   这里有一个问题,我们如何知道我们取到的是字符串中的第一 个出现一次的字母,这里要求我们在映射字符的时候,顺便将其 第一次出现的位置记录到哈希表结构中去。位置最靠前的当然就 是第一个只出现一次的字母了。   在实现过程中,可以自己实现一个定制的哈希表结构,但是 我嫌太麻烦了,就利用了一些个小技巧,利用一个Set来记录 出现了那些字符,在定义一个结构体记录每个字符出现的次数和 首次在字符串中出现的位置。

改进算法1 

如果对bitmap熟悉的话,首先应该考虑就是bitmap,可以简单快速的实现该算法。小段代码如下(DevC++ 编译通过)。 

char b[]="dcbbdcsk";
int a[256];
int i = 0;
for(i=0; i<256; i="" br="">a[i]=0; 
int l = strlen(b);
for(i = 0;ia[int(b[i])]+=1;
}
for(i = 0;iif(a[int(b[i])]==1)
{
cout<<b[i]<<endl;
break;
}
}

首先由一个256位的int数组用作bitmap。这256个位置将用于表示一个字符的ASCII码值。例如位置97表示字符a。bitmap的妙处就在于能利用数组的地址值信息。如果‘a'出现一次我们就在int[97]中增加1。这样数组a[256]中值的大于就表示该位置对应的字符出现过几次。a[int(b[i])]+=1 就是对字符出现的个数计数。第二个循环就是遍历‘dcbbdcsk’。找到第一个a[int(b[i])]==1的字符。那么这个字符即为所求。

改进2

对上面的bitmap是否还有可改进的呢? 答案是yes。 题目中要求的只是字母。所以根本不需要256个int来计数,这里只需要考虑a-zA-Z 52个字母,a-z ASCII为97-122. A-Z 为65-90. 由于大小写字母ASCII不连续。为了处理方便我们可以用一个58(122-65+1)长的数组。对应的a[int(b[i])]只需要改为a[int(b[i])-65]. 空间复杂度就由原来o(256)降到o(58)。时间复杂度不变。如果只是用52长的数组也可以,那需要分别考虑大小写,会增加时间代价。

改进3

那能再抠点空间出来吗?试试吧。我们再来看看题目要求。除了有字母的限制外。还有‘第一个只出现一次’。也就是所有字符只有3种可能

  1. 没有出现      =0
  2. 出现1次        =1
  3. 出现多于1次 >1

只有3种状态是否需要用int来表示呢?当然不用。我们知道对于那种状态只需要log(n)bit就可以解决。所以这里不需要58个int,只需要58个“2bit”,即15个byte的数组。这样就需要用逻辑操作。 这里令x=int(b[i])-65  Byte a[15]以初始化为0 a[int(b[i])]+=1 改为 

if(((a[x/4+1] & ox10000000 >>((x%4−1)x2)) == 0)
a[x/4+1]+=ox10000000 >>((x%4)x2−1)  

a[int(b[i])]==1改为 ((a[x/4+1] & ox10000000 >>((x%4−1)x2)) == 1

这样空间复杂度将再度降低。 总结,做题之前一定要看清题目要求。

Double check is never a bad thing ^_^

原创粉丝点击