简单算法问题-如何统计一个字符串中每个字符出现的次数?

我的思路是,先遍历这个字符串,将每个字符作为Map的键,因为Map键是唯一的,并且是存在检测键是否存在这个方法,所以可以用这个特性,先判断字符是否作为键在Map中存在,如果存在,就获取当前字符对应的值,不存在,则将字符存入键,值设置为1,最后再将Map集合打印输出。代码如下:

public static void main(String[] args){
  //创建map集合,键用Character,因为要将字符作为键,Integer作为值,因为需要存放字符出现次数
  Map<Character,Integer> map = new HashMap<>();
  String a = "HelloWorld,Kitty,Hi,how are you?";
  //声明统计变量,赋初值
  int count = 0;
  //遍历字符串  将字符串转字符数组  toCharArray()
  for(char s : a.toCharArray()){
    //判断map是否存在键
    if(map.containsKey(s)){
      //存在,根据键取出值,进行+1操作
      count = map.get(s);
      map.put(s,++count);
    }else{
      //不存在,存放入键,次数赋值为1
      map.put(s,1);
    }
  }
    //打印输出,使用forEach循环
    map.forEach((key,value) -> System.out.println("char:" + key + ", count:" + value));
}

运行结果:

char: , count:2
char:a, count:1
char:d, count:1
char:e, count:2
char:H, count:2
char:h, count:1
char:i, count:2
char:K, count:1
char:l, count:3
char:,, count:3
char:o, count:4
char:r, count:2
char:t, count:2
char:u, count:1
char:W, count:1
char:w, count:1
char:y, count:2
char:?, count:1

是可以的,但是感觉有点麻烦,让AI帮忙简化看看。AI给出的方案是,主要是在判断键是否存在那里,改用merge()方法,查看一下运行也正常输出结果。

        Map<Character,Integer> map = new HashMap<>();
        String a = "HelloWorld,Kitty,Hi,how are you?";
        for(char s : a.toCharArray()){
            map.merge(s,1,Integer::sum);
        }

        map.forEach((key, value) -> System.out.println("char:" + key + ", count:" + value));

这个时候再仔细看一下merge()方法,merge,就是合并的意思。

default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction)

  • key 是 我们要合并的键
  • value 是 键不存在的时候,插入的值
  • remappingFunction:是一个 BiFunction,有点不明白,但是作用是 合并现有值和新值

现有值,新值是什么?

  • 参数1:现有值(如果键已经存在于 map 中)。
  • 参数2:新值(您尝试插入的值)。

现有值和新值的来源

  • 现有值:
    • 如果 map 中已经存在键 key,则现有值是 map.get(key) 返回的值。
    • 如果 map 中不存在键 key,则现有值为 null。
  • 新值:
    • 新值是您在 merge 方法中提供的 value 参数。
    • 在代码中,新值始终是 1,因为在 merge 方法中传递了 1 作为新值。

大致理解了,但是为什么remappingFunction这里使用的是Integer::sum呢,再来看一下解释

  • Integer::sum 是一个方法引用,等价于以下 lambda 表达式: (a, b) -> a + b
  • 在这个上下文中,Integer::sum 用于将现有值和新值相加。具体来说:
    • 如果 map 中已经存在键 c,则 remappingFunction 会被调用,将现有值和新值相加。
    • 如果 map 中不存在键 c,则直接插入新值 1。

为什么必须是 Integer::sum

  • 类型匹配:
    • map 的值类型是 Integer。
    • remappingFunction 需要接受两个 Integer 参数并返回一个 Integer 结果。
    • Integer::sum 恰好满足这个要求,因为它接受两个 int 参数并返回一个 int 结果,而 Integer 可以自动装箱和拆箱。
  • 简洁性:
    • 使用方法引用 Integer::sum 使代码更简洁,易于阅读和理解。
    • 相比于编写一个完整的 lambda 表达式 (a, b) -> a + b,方法引用更简洁。
  • 功能性:
    • Integer::sum 提供了标准的整数加法操作,确保合并逻辑正确且高效。