【问题标题】:detect duplicate character in string检测字符串中的重复字符
【发布时间】:2015-10-11 13:51:49
【问题描述】:

我正在做《Cracking The Coding Interview》一书中的练习,我正在尝试确定字符串中是否存在重复字符。我正在使用 ArrayList 数据结构。我的方法是返回类型布尔,如果有重复则返回true,如果没有重复字符则返回false。我添加了第三条 return 语句,以便程序可以编译,但它总是返回 false。

import java.util.*;

public class QuestionOneCrackingCode {

    public static void main(String[] args) {
        String s = "abcdefga";
        ArrayList<String> c = new ArrayList<String>();
        c.add(s);

        System.out.print(check(c));
    }

    public static boolean check(ArrayList<String> g) {
        for (int i = 0; i < g.size(); i++) {
            for (int j = i + 1; j < g.size(); j++) {
                if (g.get(i) == g.get(j)) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        return false;
    }
}

【问题讨论】:

  • 注意if (...) { return true; } else { return false; }可以简化为return ...;
  • 我建议做一些更简单的事情:查看String 内部,对当前字符使用char 变量,然后从当前位置到最后一个位置或从当前位置到首先。这样可以节省时间并且更容易编码。
  • @LuiggiMendoza 我不认为这是正确的欺骗 - 即使他切换到 .equals() 它也行不通 - 真正的问题是他期望 c.add(s) 将字符串拆分为当它实际上只会导致原始字符串的单项列表时,字符甚至不会与任何内容进行比较。如果他真的在比较字符,== 是正确的
  • @CupawnTae 好吧,这个实现还有更多问题。我将重新提出问题。请提供一个使用这个 now non-dup 的答案。
  • @CupawnTae OP 比较的是Strings,而不是chars,检查参数:ArrayList&lt;String&gt; g 及其用法:g.get(i)

标签: java string arraylist char


【解决方案1】:

我用一张表来计算一个字符重复了多少次,如果一个字符出现多次则返回true,最坏情况的代码是O(n)

public static void main(String[] args) {

    String test ="abdefghijklmnoPQRSTUVWXYZa";
    System.out.println(isThereAnyCharacterRepeated(test));
}


public static boolean isThereAnyCharacterRepeated(String str){

    int repeatedCharacters[] = new int[255];
    for(int i=0;i<str.length();i++){
        int index=(int)str.charAt(i);
        repeatedCharacters[index]++;
        if(repeatedCharacters[index]>1)return true;
    }
    return false;
}

【讨论】:

    【解决方案2】:
    1. 使用字符串而不是 ArrayList。
    2. 比较失败不返回,需要继续查找,不返回false,所以总是返回false。
    3. 即使这样,这也不是最优化的解决方案,请尝试考虑桶排序以及它如何解决这个问题。这将使您的解决方案在 O(N) 而不是 O(N^2) 中运行。
    public static boolean check(String g) {
    
        for (int i = 0; i < g.length(); i++) {
            for (int j = i + 1; j < g.length(); j++) {
                if (g.charAt(i) == (g.charAt(j))) {
                    return true;
                }
            }
        }
    
        return false;
    }
    

    【讨论】:

      【解决方案3】:

      在 Java 8 中,您可以这样做:

      public static boolean check(CharSequence checkString)
      {
        return checkString.length() != checkString.chars().distinct().count();
      }
      

      即如果字符串中不同字符的数量与字符总数不同,则您知道存在重复。这不一定是最有效的方式,但很简洁。

      【讨论】:

        【解决方案4】:

        我的参与:

            public static void main(String[] args) {
                System.out.println(check("abcdefga"));                    // true
                System.out.println(check("noduplicate"));                 // false
                System.out.println(check("withduplicate"));               // true
                System.out.println(check("abcdefghijklmnopqrstuvwxyz"));  // false
                System.out.println(check("abcdefghijklmnopqrstuvwxyzz")); // true
            }
        
            /**@brief Check if a String contains duplicated characters.
             * Strong expectation for the string: The String must only contains
             * lowercase alpha characters (ie. in [a-z])
             * @returns true if a char is present more than once */
            public static boolean check(String str) {
                int presentChars = 0; // will store the table of already found characters
                int l = str.length();
                for (int i = 0; i < l; ++i) {
                    char c = str.charAt(i);
                    int offset = c - 'a';             // a=0, b=1, ... z=25
                    int mask = 1 << offset;
                    if ((presentChars& mask) != 0) {  // Oh! Char already tagged as found
                        return true;                  // No need to process further, bye!
                    }
                    presentChars|= mask;              // Tag the current char as present
                }
                return false;                         // No duplicate
            }
        
        }
        

        我对这段代码的目标是尽量减少复杂性。在最坏的情况下,该算法在 O(N) 中。此外,该函数的内存占用非常低:只有一个int 是真正需要的(presentChars),即使我使用更多以提高可读性=)

        这段代码的缺点:输入的字符串有一个很大的先决条件。我在 cmets 上对此进行了详细说明,但它仅适用于 [a-z] 范围内的字符。

        希望对你有帮助!

        【讨论】:

          【解决方案5】:

          您的解决方案比较列表中的字符串引用。列表本身只包含一个字符串。

          尝试以下方法:

          // check one string for duplicate chars
          public static boolean check(String checkString)
          {
              // result flag
              boolean foundDuplicate = false;
              // get string length
              int stringLength = checkString.length();
              // create a set for all found characters (max size is number
              // of characters in the string to check
              Set<Character> characters = new HashSet<>(stringLength);
              // loop all characters in string
              for (int i = 0; i < stringLength; i++)
              {
                  // construct a object (may be use internal JDK cache)
                  Character c = Character.valueOf(checkString.charAt(i));
                  // check if character is already found
                  if (characters.contains(c))
                  {
                      // yes, set result to TRUE
                      foundDuplicate = true;
                      // break the loop
                      break;
                  }
                  else
                  {
                      // not found, add char to set
                      characters.add(c);
                  }
              }
              return foundDuplicate;
          }
          

          这受字符串长度和堆大小的限制。但我假设所有 UTF-8 字符都可以放入堆中。

          @Maarten Bodewes 你是对的。检查可以简化为:

                  // add character to set and check result
                  if (!characters.add(c))
                  {
                      // returned false: character already exists
                      foundDuplicate = true;
                      // break the loop
                      break;
                  }
                  // no else necessary
          

          【讨论】:

          • 你可以简单地使用add的返回值。
          【解决方案6】:

          这是我的代码版本的结果。

          abcdefga true
          abcdefgh false
          abcdefdh true
          
          1. 我修改了检查参数以采用单个字符串。不需要字符串列表。

          2. 在检查方法中,一旦一对字符匹配就可以退出。您必须先测试整个字符串,然后才能说没有匹配的字符。

          3. 第一个 for 循环可以在倒数第二个字符处停止。第二个 for 循环将获取最后一个字符。

          4. 因为我在比较 char 值,所以我使用 ==。如果我要比较 String 值,我会使用 .equals 方法。

          这是代码。

          package com.ggl.testing;
          
          public class QuestionOneCrackingCode {
          
              public static void main(String[] args) {
                  String s = "abcdefga";
                  System.out.println(s + " " + check(s));
                  s = "abcdefgh";
                  System.out.println(s + " " + check(s));
                  s = "abcdefdh";
                  System.out.println(s + " " + check(s));
              }
          
              public static boolean check(String s) {
                  for (int i = 0; i < (s.length() - 1); i++) {
                      for (int j = i + 1; j < s.length(); j++) {
                          if (s.charAt(i) == s.charAt(j)) {
                              return true;
                          }
                      }
                  }
                  return false;
              }
          }
          

          【讨论】:

          • 感谢您的帮助。 :)
          【解决方案7】:

          您没有将字符串分成字符,而是创建了一个包含字符串的单元素列表。无需对算法进行重大更改,您可以这样做:

          public static void main(String[] args) {
              String s = "abcdefga";
          
              System.out.print(check(s));
          }
          
          public static boolean check(CharSequence g) {
              for (int i = 0; i < g.length(); i++) {
                  for (int j = i + 1; j < g.length(); j++) {
                      if (g.charAt(i) == g.charAt(j)) {
                          return true;
                      }
                  }
              }
              return false;
          }
          

          请注意,第一个 return false; 也是不正确的,因为它会阻止算法继续通过第一次比较。

          顺便说一句,当您比较字符串时,您应该使用.equals() 而不是==

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-05-27
            • 1970-01-01
            • 2015-07-16
            • 1970-01-01
            • 2015-01-22
            • 1970-01-01
            • 2011-07-25
            • 2016-02-12
            相关资源
            最近更新 更多