字符串的统计字符-MY
题目描述
给定一个字符串str,返回str的统计字符串。例如“aaabbbbcccd”的统计字符串为“a_3_b_4_c_3_d_1”。 输入描述:
输入一行字符串(1<=长度<=10^5)。
输出描述:
输出一行字符串,代表统计字符串。
示例1
输入
offerofferzainaliiiiii
输出
o_1_f_2_e_1_r_1_o_1_f_2_e_1_r_1_z_1_a_1_i_1_n_1_a_1_l_1_i_6
示例2
输入
hhhaaa
输出
h_3_a_3
代码
流式
char[] chars = "aaaabbbbcccd".toCharArray();
IntStream.range(0, chars.length)
.boxed()
.collect(Collectors.toMap( k -> chars[k], v -> 1, (v1, v2) -> v1 + 1 ))
.entrySet().stream()
.map(x->"_"+x.getKey()+"_"+x.getValue())
.reduce((a, b) -> a+b)
.ifPresent(x-> System.out.println(x.substring(1)));
过程式
char[] chars = "aaaabbbbcccd".toCharArray();
HashMap<Character, Integer> stringIntegerHashMap = new HashMap<>();
for (int i = 0; i < chars.length; i++) {
if (!stringIntegerHashMap.containsKey(chars[i])){
stringIntegerHashMap.put(chars[i],1);
}else {
stringIntegerHashMap.replace(chars[i],stringIntegerHashMap.get(chars[i])+1);
}
}
StringBuilder s= new StringBuilder();
Set<Map.Entry<Character, Integer>> entries = stringIntegerHashMap.entrySet();
Iterator<Map.Entry<Character, Integer>> iterator = entries.iterator();
for (int i = 0; i < entries.size(); i++) {
Map.Entry<Character, Integer> next = iterator.next();
s.append("_").append(next.getKey()).append("_").append(next.getValue());
}
System.out.println(s.substring(1));
结果
a_4_b_4_c_3_d_1
总结
概述
这道算法题的关键点在于记录char数组中,无重复字符的个数。 大致流程就是指针扫描char数组中的每个字符,判断字符是否出现过,如果有就+1,而对于从来就没有出现的字符默认就是赋值1. 对于如何记录无重复字符个数,无疑使用hashmap是最合适的。 两种写法的思路其实是一样的,流式编程(函数式编程)并不会带来性能上的提升。
流式编程写法中的一些操作
IntStream.range(0, chars.length)
使用IntStream.range()方法生成范围内从一个初始值到最大值的一系列数字。上面代码中初始值是0,最大值是chars.length(要操作的字符数量)
.boxed()
此处方法为装箱,将int转为Integer,因为toMap()方法要生成一个hashmap,而hashmap使用的类型必须是包装类。对于数组的操作int足以,但是不使用boxed()编译器会报错,我觉得应该是类型推导的原因。
.collect(Collectors.toMap( k -> chars[k], v -> 1, (v1, v2) -> v1 + 1 ))
这里的重点是toMap(),它实际上接受了三个参数,第一个是key,第二个是value,第三个是当前key在hashmap里面若有重复让你选取值,v1(已存在key对应的value值)还是v2(当前key的值)。由于三个参数都是函数式接口,写起来十分简洁。
.entrySet().stream()
将hashmap转entrySet,再开启流。这样才可以对hashmap中的值操作。
.map(x->"_"+x.getKey()+"_"+x.getValue())
映射操作,将entrySet中的key和value与字符串拼接。注意,这里的类型已经转换为String了。下面开始操作的数据类型就是String。
.reduce((a, b) -> a+b)
归并操作,会从流里面取值充当参数,a是第一次流的值,b是第二次流的值,此处将他们归并为两个字符串拼接。举个例子,"_a_3"+"_b_2",拼接结果就是这样,直至将entrySet中所有的数据拼接完。
.ifPresent(x-> System.out.println(x.substring(1)));
为什么是ifPresent()?因为reduce()操作完了返回的是Optional类型的值,这里返回的是Optional<String>类型,ifPresent正是Optional的方法,作用是如果存在数据将如何处理。最后使用lambda打印从位置1开始截取的子字符串。
感想
流式编程特点是对数据处理十分方便,并且看着简洁优美,流程一次写完,甚至不需要中间变量,底层已经优化好了,通过高级抽象,我们只需要关心做什么而不是怎么做,但是对于初学者来说阅读性可能不是很好, 而过程式编程对于细节把控十分到位,尽管很啰嗦。 第一次发文章,不知道为啥图片上传不上来。如有错误,恳请指正!😊