本文详解如何在统计日期数组中最频繁星期几时,当多个星期几出现频次相同时,优先返回“周顺序最早”的那个(即按 sun→mon→tue→wed→thu→fri→sat 的自然周序取最小索引者)。
本文详解如何在统计日期数组中最频繁星期几时,当多个星期几出现频次相同时,优先返回“周顺序最早”的那个(即按 sun→mon→tue→wed→thu→fri→sat 的自然周序取最小索引者)。
在实际业务场景中(如用户活跃度分析、日志周期统计等),我们常需从一组日期中找出出现频率最高的星期几。但仅统计最大频次还不够——当存在多个星期几并列最高频时,必须定义明确的决胜规则。题目要求:在频次相同的情况下,返回周序最早的那一天(注意:不是日期时间上最早,而是星期名称在标准周序列中的位置最靠前)。
标准周序为:["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],其索引 0~6 明确表达了先后关系。因此,决胜逻辑应基于该顺序的索引值比较,而非字符串字典序(如 "Fri" 字典序小于 "Mon",但周序上 Mon 更早)。
以下是优化后的实现方案,具备清晰逻辑、可读性强且避免原代码中的典型缺陷(如重复创建 Vector、错误索引访问、未初始化 days 导致 NPE 风险等):
public static String mostFrequentDayOfWeek(SimpleDate[] dates) {
if (dates == null || dates.length == 0) {
throw new IllegalArgumentException("Dates array cannot be null or empty");
}
// 定义标准周序(索引即周序优先级:0 最早,6 最晚)
List<String> weekOrder = Arrays.asList("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
int maxCount = 0;
int minIndex = Integer.MAX_VALUE; // 记录当前最优星期在 weekOrder 中的索引
String freqDay = "";
for (SimpleDate d1 : dates) {
String day1 = dayOfWeek(d1);
int count = 0;
// 统计 day1 在整个数组中出现次数
for (SimpleDate d2 : dates) {
if (day1.equals(dayOfWeek(d2))) {
count++;
}
}
int currentIndex = weekOrder.indexOf(day1);
// 更新条件:频次更高;或频次相同但周序更早(索引更小)
if (count > maxCount || (count == maxCount && currentIndex < minIndex)) {
maxCount = count;
minIndex = currentIndex;
freqDay = day1;
}
}
return freqDay;
}✅ 关键改进说明:
- 使用 List<String> weekOrder 显式建模周序关系,indexOf() 提供 O(1) 索引查询(因列表长度固定为 7);
- 合并 if/else if 逻辑为单条件判断,语义更紧凑,避免状态不一致风险;
- 增加空值校验,提升鲁棒性;
- 移除冗余变量(如原 Vector<String> days),避免内存浪费与逻辑混淆;
- 注释明确标注“周序”与“字典序”的本质区别,防止误用 String.compareTo()。
⚠️ 注意事项:
- dayOfWeek() 方法必须严格返回上述 7 个标准化缩写(大小写敏感),否则 weekOrder.indexOf() 将返回 -1,导致逻辑异常;
- 当前算法时间复杂度为 O(n²),适用于中小规模数据(如 ≤10⁴ 日期)。若需高性能,建议改用 Map<String, Integer> 预统计频次(O(n)),再遍历 Map 比较频次+周序(O(1));
- 若业务要求“最早日期对应星期”(即真实时间最早的那个日期的星期),则需先排序 dates 再统计——本题明确要求“周序最早”,二者不可混淆。
通过此实现,例如输入 [2023-01-01(Sun), 2023-01-02(Mon), 2023-01-08(Sun), 2023-01-09(Mon)],Sun 与 Mon 均出现 2 次,因 "Sun" 在 weekOrder 中索引为 0,小于 "Mon" 的 1,故返回 "Sun",完全符合题目要求。










