【问题标题】:How can I return only one common value?我怎样才能只返回一个共同值?
【发布时间】:2017-04-04 03:56:04
【问题描述】:

我创建的示例代码返回两个字符串之间有多少个字符相似,但我怎样才能得到它,这样它就不会返回重复的相似字符?就像假设输入是 1:“hello”和 2:“lend”。当代码迭代时,它会看到总共 2 个类似的 l,在我的情况下,我怎样才能让它只返回一个“l”?

static int compare(String input1, String input2){

            int count = 0;


        for(int i = 0; i < input1.length(); i++) 
        {
            if(input2.contains(String.valueOf(input1.charAt(i)))){
                count++;
            }
        }

        return count;
    }

【问题讨论】:

  • 使用Set&lt;Character&gt; 来跟踪已经看到的字符,例如使用HashSet
  • 只是为了确认,您希望忽略大小写,对吧? “L”和“l”实际上根本不应该匹配,因为它们是不同的情况。
  • 我的错,输入不会有大写。
  • 不相关:检查input2是否包含字符input1.charAt(i)的更好方法是使用indexOf(),即if (input2.indexOf(input1.charAt(i)) != -1)

标签: java function for-loop


【解决方案1】:

为了获得最佳性能,如果字符串可能很长,并且您需要支持所有个 Unicode 字符,请使用 Set&lt;Integer&gt;retainAll(),其中整数值是 Unicode 代码点。 p>

在 Java 8 中,可以使用以下代码完成:

private static int countDistinctCommonChars(String s1, String s2) {
    Set<Integer> set1 = s1.codePoints().boxed().collect(Collectors.toSet());
    Set<Integer> set2 = s2.codePoints().boxed().collect(Collectors.toSet());
    set1.retainAll(set2);
    return set1.size();
}

如果您希望返回常用字符,您可以这样做:

private static String getDistinctCommonChars(String s1, String s2) {
    Set<Integer> set1 = s1.codePoints().boxed().collect(Collectors.toSet());
    Set<Integer> set2 = s2.codePoints().boxed().collect(Collectors.toSet());
    set1.retainAll(set2);
    int[] codePoints = set1.stream().mapToInt(Integer::intValue).toArray();
    Arrays.sort(codePoints);
    return new String(codePoints, 0, codePoints.length);
}

测试

public static void main(String[] args) {
    test("hello", "lend");
    test("lend", "hello");
    test("mississippi", "expressionless");
    test("expressionless", "comprehensible");
    test("????", "?????"); // Extended, i.e. 2 chars per code point
}
private static void test(String s1, String s2) {
    System.out.printf("Found %d (\"%s\") common chars between \"%s\" and \"%s\"%n",
                      countDistinctCommonChars(s1, s2),
                      getDistinctCommonChars(s1, s2),
                      s1, s2);
}

输出

Found 2 ("el") common chars between "hello" and "lend"
Found 2 ("el") common chars between "lend" and "hello"
Found 3 ("ips") common chars between "mississippi" and "expressionless"
Found 8 ("eilnoprs") common chars between "expressionless" and "comprehensible"
Found 2 ("??") common chars between "????" and "?????"

请注意,最后一个测试使用来自 'Domino Tiles' Unicode Block(U+1F030 到 U+1F09F)的 Unicode 字符,即在 Java 字符串中存储为 surrogate pairs 的字符。

【讨论】:

    【解决方案2】:

    另一种方法是创建 input2 的副本并删除找到的字符。我相信这应该比使用 ArrayList 更有效。

    static int compare(String input1, String input2){
    
            int count = 0;
    
            String check = input2;
            for(int i = 0; i < input1.length(); i++) 
            {
                if(check.contains(String.valueOf(input1.charAt(i)))){
                    check = check.replace(String.valueOf(input1.charAt(i)), "");
                    count++;
                }
            }
            return count;
    }
    

    【讨论】:

    • 每次检测到重复时都会创建一个新字符串,这根本没有效率。在所有提议的方法中,我的第二个将是迄今为止最快的。
    【解决方案3】:

    我建议创建一个 ArrayList 来跟踪在遍历字符串时已经“捕获”的字符。

    您必须在 for 循环之前初始化字符数组列表。如果发现重复字符,请将其添加到 ArrayList。更改当前代码中 for 循环内的 if 语句,以包括 ArrayList 是否实际包含该字母。因此,它不会重复和增加计数。

    请记住字符区分大小写。

    【讨论】:

      【解决方案4】:

      您可以使用 this 正则表达式从字符串中删除任何重复字符。

      (.)(?=.*\1)
      

      删除所有重复项后,您可以继续正常执行。

      static int compare(String input1, String input2){
          int count = 0;
      
          input1 = input1.replaceAll("(.)(?=.*\\1)", "");
          input2 = input2.replaceAll("(.)(?=.*\\1)", "");
      
      
          for(int i = 0; i < input1.length(); i++) 
      
          ...
      

      【讨论】:

        【解决方案5】:
        static int compare(String input1, String input2){
        
                int count = 0;
                String taken = "";
        
                for(int i = 0; i < input1.length(); i++) 
                {
                    if(input2.contains(String.valueOf(input1.charAt(i)))){
                        if(!taken.contains(String.valueOf(input1.charAt(i)))){
                            taken = taken.concat(String.valueOf(input1.charAt(i)));
                            count++;
                        }
                    }
                }
        
                return count;
            }
        

        【讨论】:

          【解决方案6】:

          如果您要处理各种字符,那么使用集合可能是最简单的。如果你只处理 a-z 那么你可以这样做:

          int count = 0;
          for (char c = 'a'; c <= 'z'; c++)
              if (input1.indexOf(c) >= 0 && input2.indexOf(c) >= 0)
                  count++;
          return count;
          

          【讨论】:

          • 目标是不重复计算同一个字母。 helloballad 应该只计算一个 L
          • 一如既往...低效的方法获得了赞成...人们不想学习。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-04-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多