检查字符串中的重复字符

时间:2012-11-08 07:10:00

标签: algorithm bit-manipulation

在一次采访中,我被要求检查天气,给定的字符串有重复的字符。谷歌关于这个问题,我开始了解一个使用位操作的问题。

bool check(char*name)
{
     int i;
     int checker=0;
     for(i=0;name[i]!=0;i++)
     {
        int val=name[i]-'a';
        if((checker&(1<<val))>0)return false;
          checker|=(1<<val);
     }
     return true;
 }

我检查了这段代码并且工作正常。但我不理解这一行背后的逻辑。

> if((checker&(1<<val))>0)return false;
>               checker|=(1<<val);

第二个疑问是,如果字符串太长或包含Unicode(2字节宽字符),这是否可行?

2 个答案:

答案 0 :(得分:1)

该算法使用每个ascii字符1位来指示该集合的存在。所以它至少适用于英文小写字母 - 其中26个字符和连续的ascii代码。 a = 000001,b = 000010,c = 000100等 &#39; aacaaccc&#39;和&#39; ac&#39;和&#39; ca&#39;无论a和c的出现次数如何,都将编码为000101。因此,字符串长度并不重要。

你对2字节字符是正确的。拉丁字符集也会引起问题,但混合情况(上下)的问题可以通过屏蔽第5位(32)转换为大写(或者使用32转换为小写)来轻松解决。 / p>

ASCII字符表为所有字符分配一个整数:

@ = 64 = 01**0**00000   ...  
A = 65 = 01**0**00001   ...   a =  97 = 01**1**00001
B = 66 = 01**0**00010   ...   b =  98 = 01**1**00010 
.. 
Z = 90 = 01**0**11010   ...   z = 122 = 01**1**11010

大写和小写字符仅在该特定位和'a' - 32 == 'A'或其他方面有所不同:'B' + 32 == 'b''B' | 32 == 'b',其中|是按位OR运算符。

答案 1 :(得分:1)

这称为位掩码。这里的检查器是位掩码。

第一个表达式:if((checker&(1<<val))>0)获取该位,第二个表达式checker|=(1<<val)设置该位。

左移操作符提高了2 ^ val。所以你有类似001000(对于'd')。

&amp;只要检查器的第i位和新的val(001000)都是1,运算符就返回true。因此,您知道该字符是否已被覆盖。

|运算符只是将第i位设置为1.因此,如果在某些情况下检查器是010000,现在它变为011000。