【问题标题】:Check if string contains all unique characters检查字符串是否包含所有唯一字符
【发布时间】:2019-08-19 23:12:56
【问题描述】:

// O(N) - 没有额外的数据结构...

private boolean isUniqueWithoutDS(String str){
    boolean value = true;

    int checker = 0;

    for (int i = 0; i < str.length(); i++) {
        int c = str.charAt(i) - 'a';
        System.out.println("checker is : " + checker);
        System.out.println("1<<c is " + (1<<c));   
        if((checker & (1 << c))>0){
            value = false;
            break;
        }
        checker = checker | 1<<c;
    }

    return value;
}

这是我的代码并且工作正常,我无法理解它如何用于大写和小写字母组合的字符串。例如“Zizu”它可以工作。对于所有小写字母的字符串,它都有效,我也知道它是如何工作的。

【问题讨论】:

    标签: java string algorithm


    【解决方案1】:

    嗯,答案可能取决于语言,但在 Java 中 (JLS 15.19. Shift Operators):

    如果左手操作数的提升类型是int,那么只有右手操作数的五个最低位用作移位距离。就好像右手操作数经过位逻辑与运算符&amp;(§15.22.1)和掩码值0x1f0b11111)。因此,实际使用的移位距离始终在031 的范围内。

    所以就像你执行c = c &amp; 0x1fc = c % 32,所以大写的A和小写的a都变成cc0,用于&lt;&lt;运算符.

    我假设对于 32 位 int 类型,其他语言也可以类似地工作。

    【讨论】:

    • 那么,大写和小写字母的工作方式相同吗?很好的答案。谢谢。
    【解决方案2】:

    另一种检查字符串是否包含所有唯一字符的方法——在O(N)中:

    1. 使用无限循环
    2. 使用二元 i (i=0) 和 j=(n-1 [其中 n-是字符串长度])
    3. 检查每个第 i 个字符是否等于第 j 个字符

      3.1 如果 [i-th char == j-th && i != j char],打破循环导致字符串包含重复的字符。 (i != j 表示与同一个字符比较)

      3.2 递减 j 并设置 j 为 n-1 并且 i += 1,当 j = 0 [这部分很棘手]

    4. 重复第 3 步,除非 i 变为第 n-1 个尺寸

    代码

        String s = "abcde";
    
        int i = 0;
        int j = s.length()-1;
    
        boolean flag = true;
    
        while(true) {
            if(i == s.length()-1)
                break;
            // DUPLICATE FOUND
            if(i != j && s.charAt(i) == s.charAt(j)) {
                flag = false;
                break;
            }else {
                j--;
                // COMPARING DONE AGAINST i-TH CHAR TO ALL OTHER CHARS, INCREMENT i NOW
                if(j == 0) {
                    j = s.length()-1;
                    i += 1;
                }
            }           
        }
    
        if(flag)
            System.out.println("unique");
        else
            System.out.println("non-unique");
    

    【讨论】:

    • 这里的代码是 O(N^2)。它使用单个 while 模拟双重 for 循环,例如“for (i = 0; i = 0; j--)”,但处理量是一样。
    • 等着有人反对我!是啊,你说得对。只不过是将 O(n^2) 扩展到 O(n) :D 但解决方案在 O(n) 中:P
    • :) 你是对的,因为字母表中只有 O(1) 个字符(因此在无限循环中断之前不会花费很长时间)- 赞成。
    • 它仍然是一个 O(n^2) 风格的算法,像 qwertyman 所说的对双循环的重写,它只是试图混淆算法的双循环性质.当然,如果输入仅限于字母,复杂性就会受到限制,但性能仍然比问题代码慢得多。如果输入不限于字母(问题代码暗示它是,但问题没有规定),那么性能会变得更糟。当然,在这种情况下问题代码会失败,因此需要更好的解决方案,但事实并非如此。
    【解决方案3】:

    我建议使用大小为 256 的数组来存储每个字符的计数(假设有 256 个可能的字符),在循环开始时将其设置为值 0。然后,只需在获取每个下一个字符时增加每个位置。最后,有一个快速的技巧可以检查位置中的值是 0 还是 1(例如,freq[i] == !!freq[i])。这个 if 语句 [freq[i] == !!freq[i]] 应该适用于数组中的所有 256 个项目。

    更新:

    unsigned int isDistinctStr(char *str);
    unsigned int isDistinctStr(char *str) {
        unsigned int ct, freq[256], i, j;
        char ch;
    
        for (i = 0; i < 256; i++) {freq[i] = 0;}
        for (ct = 0; ch = *str; str++) {
            j = (unsigned int) (ch & 0xffu);
            freq[j]++;
        }
        for (j = 0; j < 256; j++) {
            if (freq[j] == !!freq[j]) {ct++;}
        }
        return (ct == 256) ? 1 : 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-04
      • 1970-01-01
      • 1970-01-01
      • 2017-01-18
      • 2011-11-09
      • 2013-05-18
      • 1970-01-01
      • 2017-01-20
      • 2013-10-26
      相关资源
      最近更新 更多