该题为leetcode819,属于一道简单题,虽然题比较简单,但是用到的api对于大部分新手小伙伴来说不太熟悉,而且细节也不少,下面展示三个方法,性能是逐渐提升的。
1. 将 paragraph 截取为一个个单词 2. 将单词加入 map 集合,单词本身作为 key,出现次数作为 value,避免禁用词加入 3. 在 map 集合中找到 value 最大的,返回它对应的 key 即可
实现特点:
1.分割单词时用的是正则表达式,利用逆向思维 ,优点:代码简单 缺点:性能不高
2.利用stream流的api进行实现,优点:代码简洁【当然我这里的注释较多】 缺点:性能不高
public String mostCommonWord1(String paragraph, String[] banned) {//14ms
//利用正则表达式--不管大小写,所以统一转换为小写字符
String[] split = paragraph.toLowerCase().split("[^A-Za-z]+");
Set set = Set.of(banned);//1.9以上版本,直接用,把字符串数组转换为set集合--不能在循环内,否则影响效率
HashMap map = new HashMap<>();
for (String key : split) {
// Integer value = map.get(key);
// if (value == null) {
// value = 0;//为value设初值
// }
// map.put(key, value + 1);//计数
//用更简洁的api来表示---map中以compute开头的方法
if (!set.contains(key)) {//避免禁用词加入
//接收两个参数:1.要放入的key 2.lambda表达式--会把当时的键值传进来
map.compute(key, (k, v) -> v == null ? 1 : v + 1);
}
}
//map.entrySet 键值的集合 将此集合转化为流,调用流中的max方法去找最大的entry max接受一个参数-->比较器对象
//调用现成的比较器:Map.Entry.comparingByValue()--->根据值进行比较,然后确定最大值
Optional> optional = map.entrySet().stream().max(Map.Entry.comparingByValue());
//返回的是一个optional对象----找到entry-->但是最终只要entry中的key
//所以对optional进行map操作, Map进行筛选,只要key部分,optional为可选,entry的存在性不确定,如果没entry返回null
return optional.map(Map.Entry::getKey).orElse(null);
}
优化点:不用lambda,利用传统的方法,在map里找一个出现次数最多的entry
public String mostCommonWord2(String paragraph, String[] banned) {//12ms
//利用正则表达式--不管大小写,所以统一转换为小写字符
String[] split = paragraph.toLowerCase().split("[^A-Za-z]+");
Set set = Set.of(banned);//1.9以上版本,直接用,把字符串数组转换为set集合--不能在循环内,否则影响效率
HashMap map = new HashMap<>();
for (String key : split) {
if (!set.contains(key)) {//避免禁用词加入
//接收两个参数:1.要放入的key 2.lambda表达式--会把当时的键值传进来
map.compute(key, (k, v) -> v == null ? 1 : v + 1);
}
}
int max = 0;//先假定最大的value值为0
String maxKey = null;
for (Map.Entry e : map.entrySet()) {
Integer value = e.getValue();
if (value > max) {
max = value;
maxKey = e.getKey();
}
}
return maxKey;
}
优化点:截取单词的时候--不利用正则表达式【看起来简洁,但是效率较低】 自己拼接每一个单词
public String mostCommonWord(String paragraph, String[] banned) {//5ms
//利用正则表达式--不管大小写,所以统一转换为小写字符
Set set = Set.of(banned);//1.9以上版本,直接用,把字符串数组转换为set集合--不能在循环内,否则影响效率
HashMap map = new HashMap<>();
char[] chars = paragraph.toLowerCase().toCharArray();//拿到字符串的字符数组
StringBuilder sb = new StringBuilder();
for (char ch : chars) {
if (ch >= 'a' && ch <= 'z') {
//做字符串拼接,利用StringBuilder比用+效率更高
sb.append(ch);
} else {
String key = sb.toString();
if (!set.contains(key)) {
map.compute(key, (k, v) -> v == null ? 1 : v + 1);
}
// sb = new StringBuilder();//创建新对象,重新拼接
sb.setLength(0);//把旧的内容清空,下次拼接的时候就从0索引开始重新拼接,不用一直创建,提高性能
}
}
if (sb.length() > 0) {//确保不会丢单词--做好收尾工作
String key = sb.toString();
if (!set.contains(key)) {
map.compute(key, (k, v) -> v == null ? 1 : v + 1);
}
}
int max = 0;//先假定最大的value值为0
String maxKey = null;
for (Map.Entry e : map.entrySet()) {
Integer value = e.getValue();
String key = e.getKey();
if (!Objects.equals(key, "") && value > max) {//此时的key可能为"" key是字符串,所以用包装类型来比较
max = value;
maxKey = e.getKey();
}
}
return maxKey;
}
当然这三个方法都是通过leetcode的,大家可以用leetcode的测试用例
public static void main(String[] args) {
E08Leetcode819 e08 = new E08Leetcode819();
String key = e08.mostCommonWord("Bob. hIt, baLl", new String[]{"bob", "hit"});
// String key = e08.mostCommonWord("Bob", new String[]{"hit"});
System.out.println(key); // ball
}