面试题:按字符出现次数升序生成指定字符串的字符图案
问题拆解与解决方案
你的代码主要卡在三个地方:频率统计效率低、排序逻辑未实现、图案生成缺失,下面一步步给你修正:
一、高效统计字符频率(替换嵌套循环)
原来的嵌套循环遍历字符串统计频率,不仅时间复杂度高(O(n²)),还容易出现重复统计的问题。用单次遍历+HashMap的getOrDefault方法就能简洁完成统计:
String test = "abbccbddddeeeee"; Map<Character, Integer> freqMap = new HashMap<>(); // 一次遍历完成所有字符的频率统计 for (char c : test.toCharArray()) { // 字符存在则取当前值+1,不存在则默认0+1 freqMap.put(c, freqMap.getOrDefault(c, 0) + 1); }
二、按频率升序排序字符
HashMap本身是无序的,你原来的代码试图维护两个独立列表排序,但仅实现了寻找最小值的逻辑,没有完成元素交换,等于没真正排序。直接将Map的键值对转为列表,自定义排序规则即可:
// 将Map的键值对转为列表,方便排序操作 List<Map.Entry<Character, Integer>> sortedEntries = new ArrayList<>(freqMap.entrySet()); // 排序规则:优先按出现次数升序,次数相同时按字符本身顺序(可选,根据需求调整) sortedEntries.sort((entry1, entry2) -> { int freqDiff = entry1.getValue() - entry2.getValue(); if (freqDiff != 0) { return freqDiff; } // 次数相同时按字母顺序排列,避免排序结果混乱 return entry1.getKey() - entry2.getKey(); });
三、生成指定对齐图案
要实现题目要求的右对齐效果,先找到出现次数最多的字符长度,以此为基准计算每行需要补充的空格数,再重复打印对应字符:
// 获取最大出现次数,用于计算每行的空格补位 int maxCount = sortedEntries.stream() .mapToInt(Map.Entry::getValue) .max() .orElse(0); // 遍历排序后的结果,逐行打印图案 for (Map.Entry<Character, Integer> entry : sortedEntries) { char c = entry.getKey(); int count = entry.getValue(); // 空格数 = 最大次数 - 当前字符的出现次数 int spaceNum = maxCount - count; // 先打印空格补位,再打印重复的字符 System.out.print(" ".repeat(spaceNum)); System.out.println(String.valueOf(c).repeat(count)); }
原有代码的核心问题
- 频率统计逻辑冗余:嵌套循环重复遍历字符串,效率低下,
getOrDefault方法可一步完成统计 - 排序逻辑未落地:仅尝试寻找最小值,未对列表元素进行交换排序,直接操作Map条目列表是更简洁的方式
- 图案生成逻辑缺失:完全没有实现右对齐和字符重复打印的逻辑,需要通过空格补位+字符串重复完成
运行上述完整代码,输入"abbccbddddeeeee"会得到与题目一致的输出:
a cc bbb dddd eeeee
内容的提问来源于stack exchange,提问作者Avisek Adhikari
相关产品推荐
相关产品推荐

