Java 是否可以从同一循环中的Hashmap中找到值的第一个实例?

Java 是否可以从同一循环中的Hashmap中找到值的第一个实例?,java,hashmap,Java,Hashmap,好的,我有一个面试编码问题,这个问题说明在一个循环中,我必须找到一个非重复字符的第一个实例。例如,如果字符串是abcab,它将返回c,因为a和b重复 我有下面的代码,它遍历整个字符串,并将出现的字符量输入到哈希映射中,它就可以工作了 private static boolean findFirstCharacter(String s) { HashMap<Character, Integer> map = new HashMap<Character, Integer

好的,我有一个面试编码问题,这个问题说明在一个循环中,我必须找到一个非重复字符的第一个实例。例如,如果字符串是abcab,它将返回c,因为a和b重复

我有下面的代码,它遍历整个字符串,并将出现的字符量输入到哈希映射中,它就可以工作了

private static  boolean findFirstCharacter(String s) {
     HashMap<Character, Integer> map = new HashMap<Character, Integer>();

       for(int i = 0; i < s.length(); i++) {
           char c = s.charAt(i);
            if(!map.containsKey(c)){
                map.put(c,1);

            }else{
               int value =  map.get(c);
               value++;
               map.put(c,value);


            }



        }


}

现在很明显,我可以再次迭代并找到第一个实例,其中键的值为1,但它必须是一个循环。鉴于我所拥有的,是否还有其他方法可以做到这一点,或者我是否处理得不正确?

这里有一种方法可以在单个循环中做到这一点

该方法可以处理补充平面中的Unicode字符,并已修改为返回第一个非重复字符,而不是布尔字符

注意:代码需要Java8+

试验

System.out.printlnfindFirstCharacterabcab; System.out.printlnfindFirstCharacterabcbca;
System.out.printlnfindFirstCharacter棘手的部分是,需要过滤出多次出现的字符

计算发生次数的方法强制对贴图进行第二次迭代以过滤结果

此外,由于不记得字符的实际索引,因此也不符合要求

我会使用未经测试的额外集合:

 List<Character> seenCharacters = new ArrayList<>();
循环结束后,我们作弊:

 List<Character> seenCharacters = new ArrayList<>();
 List<Character> singleCharacters = new ArrayList<>();
 for(Character c : s.toCharArray()){
   if(seenCharacters.contains(c)){  // at least second occurrence
     singleCharacters.remove(c); 
   } else {                         // first occurence
     seenCharacters.add(c);
     singleCharacters.add(c);
   }
 }
 retun singleCharacters.isEmpty()?
            ' ':
            singleCharacters.get(0); 
但是,等等,我们不需要输出位置,所以我们不需要地图,这使它更容易

private static  boolean findFirstCharacter(String s) {
    List<String> listChars = Arrays.asList(s.split(""));
    Map<String, Long> map = listChars.stream().collect(Collectors.groupingBy(c -> c, Collectors.counting()));

    for(String key : map.keySet()) {
        if(map.get(key) == 1) {
            System.out.println("Result: " + key);
            return true;
        }
    }
    return false;
}

使用这个所需的Java8可以实现一个可能的、优雅的解决方案

// better method name would be findFirstUniqueCharacter
private static char findFirstCharacter(String s) {
    HashSet<Character> unique = new LinkedHashSet<>(), seen = new HashSet<>();
    for(int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if(seen.add(c)) unique.add(c); else unique.remove(c);
    }
    return unique.isEmpty()? '_': unique.iterator().next();
}
关键是使用LinkedHashSet保存所有唯一字符,它记住插入顺序,因此允许检索第一个字符:

seen.addc仅在集合中不包含字符时添加该字符,并返回是否已添加该字符。所有集合通常都会忘记返回是否添加了元素的约定,这与Set的约定一起使得附加的contains检查过时

因此,如果seen.addc成功,我们将该字符添加到唯一字符集,否则,我们将其删除


在循环结束时,“唯一”包含遭遇顺序中所有剩余的唯一字符,因此我们可以简单地返回其第一个元素。

就是这样!为什么findFirstCharacter方法会返回布尔值?它不应该返回字符或者位置吗?@Andreas你是对的,它应该返回字符,但是我现在只是写了这个方法,将它作为一个方法来表示,因为它最初只是在主类中。哈哈哈,我一点都不懂。我一定会调查的。处理代码点的想法很好。顺便说一句,您的代码在Java 8上运行良好。您可以使用一组唯一字符和所有字符,而不是中的唯一字符和重复字符,但使用代码点而不是字符值来简化代码。@Holger不能在Java 8上运行,因为直到Java 9才添加。这不是真的。可能不太明显,因为它是从CharSequence继承的,而在Java 9中,String类使用更高效的实现覆盖它。但它在两个版本中都可用。哦,对不起,我应该在帖子中声明它应该返回字符,如果它不存在,则所有字符重复,然后它返回字符“\u”您在上一个代码段中将seenCharacters和singleCharacters集合混在一起,只需与第一个代码段进行比较即可。除此之外,我不会对重复的包含和删除操作使用ArrayList。由于groupingBy返回的映射类型未指定,因此没有保证顺序,因此,此解决方案返回任意唯一字符,而不是第一个。
 List<Character> seenCharacters = new ArrayList<>();
 List<Character> singleCharacters = new ArrayList<>();
 for(Character c : s.toCharArray()){
   if(seenCharacters.contains(c)){  // at least second occurrence
     singleCharacters.remove(c); 
   } else {                         // first occurence
     seenCharacters.add(c);
     singleCharacters.add(c);
   }
 }
 retun singleCharacters.isEmpty()?
            ' ':
            singleCharacters.get(0); 
private static  boolean findFirstCharacter(String s) {
    List<String> listChars = Arrays.asList(s.split(""));
    Map<String, Long> map = listChars.stream().collect(Collectors.groupingBy(c -> c, Collectors.counting()));

    for(String key : map.keySet()) {
        if(map.get(key) == 1) {
            System.out.println("Result: " + key);
            return true;
        }
    }
    return false;
}
// better method name would be findFirstUniqueCharacter
private static char findFirstCharacter(String s) {
    HashSet<Character> unique = new LinkedHashSet<>(), seen = new HashSet<>();
    for(int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if(seen.add(c)) unique.add(c); else unique.remove(c);
    }
    return unique.isEmpty()? '_': unique.iterator().next();
}