哈希集包含准确的字符放置和不正确的字符放置

Hashset contains with exact character placement and incorrect character placement

我有一个 class 来确定 2 个字符数组中有多少个匹配字符。使用 HashSet contains 方法,如果一个字符数组包含第二个数组中的字符,则显示该字符。
问题是如果我们有两个匹配的字符出现在多个位置。

例如,如果array 1 = adcdarray 2 = a05dddd出现3次,而不是2次。
我将如何修改它以考虑正确的字符数?代码在应该产生 "add" 时产生 "addd" 对于不正确的字符,结果将是 "a--dd"

    HashSet<Character> hash = new HashSet<Character>();        
    String word1 = "adcd";
    String word2 = "a05ddd";
    char[] ch1 = word1.toCharArray();
    char[] ch2 = word2.toCharArray();
    Character character = null;
    String charLocation = "";
    int count = 0;

    for (int i = 0; i < ch1.length; i++) 
    {
        hash.add(ch1[i]); 
       
    }
    for (int i = 0; i < ch2.length; i++) 
    {
        character = ch2[i]; 
        if (hash.contains(character)) 
           {
            charLocation = charLocation + character;
             count++;
            } 
        if (!hashSet.contains(character)) 
            correctCharPlacements = correctCharPlacements + "-";
    }

很可能需要收集关于字符出现频率的数据--所以set应该换成map。然后可以根据常见字符 两个单词中字符的最小频率来构建结果字符串:

// helper method to build frequency map for a word/string
private static Map<Character, Integer> freqMap(String word) {
    return word.chars()
               .mapToObj(c -> (char)c)
               .collect(Collectors.toMap(x -> x, x -> 1, Integer::sum, LinkedHashMap::new));
}

static String common(String w1, String w2) {
    if (null == w1 || null == w2) {
        return null;
    }
    Map<Character, Integer> map1 = freqMap(w1);
    Map<Character, Integer> map2 = freqMap(w2);
    Set<Character> commonChars = new LinkedHashSet<>(map1.keySet());
    commonChars.retainAll(map2.keySet());

    return commonChars.stream()
                      .map(x -> String.valueOf(x).repeat(Math.min(map1.get(x), map2.get(x))))
                      .collect(Collectors.joining(""));
}

测试:

System.out.println("common = " + common("adcd", "a05ddd"));

输出:

common = add

更新

由于 String::repeat 从 Java 11 开始可用,因此可以使用 String::join + Collections.nCopies 将其替换为 Java 8 兼容代码:

    static String common(String w1, String w2) {
        if (null == w1 || null == w2) {
            return null;
        }
        Map<Character, Integer> map1 = freqMap(w1);
        Map<Character, Integer> map2 = freqMap(w2);
        Set<Character> commonChars = new LinkedHashSet<>(map1.keySet());
        commonChars.retainAll(map2.keySet());
 
        return commonChars.stream()
                          .map(x -> String.join("", Collections.nCopies(Math.min(map1.get(x), map2.get(x)), String.valueOf(x))))
                          .collect(Collectors.joining(""));
    }

Online demo:

System.out.println("Java version: " + System.getProperty("java.version"));
System.out.println("common = " + common("adcd", "a05ddd"));

输出:

Java version: 1.8.0_201
common = add

更新 2

为了保持结果中第二个字符串的字符顺序,将缺失的字符替换为'-',可以实现如下方法:

static String common2(String w1, String w2) {
    if (null == w1 || null == w2) {
        return null;
    }
    Map<Character, Integer> map1 = freqMap(w1);

    StringBuilder sb = new StringBuilder();
    for (char c : w2.toCharArray()) {
        if (map1.containsKey(c) && map1.get(c) > 0) {
            sb.append(c);
            map1.merge(c, -1, Integer::sum); // decrement the character counter in the first map
        } else if (!map1.containsKey(c)) { // character missing in the first word
            sb.append('-');
        }
    }
    return sb.toString();
}

测试

String[][] tests = {
    {"adcd", "ad05dd"},
    {"adcd", "d05add"},
    {"adcd", "d05dadd"},
};
for (String[] test : tests) {
    System.out.printf("common(%s, %s) = %s%n", test[0], test[1], common(test[0], test[1]));
}

输出:

common(adcd, ad05dd) = ad--d
common(adcd, d05add) = d--ad
common(adcd, d05dadd) = d--da