
本文介绍在统计日期数组中最频繁出现的星期几时,当多个星期几出现频次相同时,如何依据“周日→周一→…→周六”的自然顺序(即 sun < mon < tue < ... < sat)选择索引最小者作为结果,提供可直接运行的java实现与关键逻辑解析。
本文介绍在统计日期数组中最频繁出现的星期几时,当多个星期几出现频次相同时,如何依据“周日→周一→…→周六”的自然顺序(即 sun < mon < tue < ... < sat)选择索引最小者作为结果,提供可直接运行的java实现与关键逻辑解析。
在实际业务场景中(如用户活跃度分析、排班系统或日志聚合),我们常需从一批日期中找出出现频率最高的星期几。但标准频次统计仅能解决“谁最多”,无法处理“多个一样多时选谁”的需求。题目明确要求:发生频次并列时,返回星期顺序上最早的那一天(例如 Tue 与 Fri 同为最高频,则选 Tue;若 Sun 与 Mon 并列,则选 Sun)。这本质上是一个「带优先级的最值选取」问题——优先级由星期的自然循环顺序定义。
为实现该逻辑,核心思路是:将星期字符串映射到一个有序索引序列,使比较操作可转化为整数大小比较。Java 中最简洁的方式是预定义一个不可变的 List<String>,按 Sun, Mon, Tue, Wed, Thu, Fri, Sat 顺序排列,并利用 indexOf() 快速获取任意星期的序号(0~6)。这样,“最早”即对应“索引最小”。
以下是优化后的完整实现(已修正原代码中的逻辑缺陷与语法错误):
import java.util.*;
public static String mostFrequentDayOfWeek(SimpleDate[] dates) {
if (dates == null || dates.length == 0) {
throw new IllegalArgumentException("Dates array cannot be null or empty");
}
// 定义星期顺序:索引越小,优先级越高("earliest")
List<String> weekOrder = Arrays.asList("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
int maxCount = 0;
int minIndex = Integer.MAX_VALUE; // 记录当前最优星期的索引
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) {
maxCount = count;
minIndex = currentIndex;
freqDay = day1;
}
// 若频次相同 → 比较星期索引,取更小者(即更早的星期)
else if (count == maxCount && currentIndex < minIndex) {
minIndex = currentIndex;
freqDay = day1;
}
}
return freqDay;
}✅ 关键改进说明:
- 消除冗余 Vector 创建:原代码在 else if 分支中反复新建 Vector 并错误调用 days.get(i)(i 是外层循环索引,与当前 day1 无关),导致逻辑崩溃。新版本全程复用 weekOrder,仅做 indexOf 查询,安全高效。
- 显式边界防护:增加空数组/空输入校验,提升鲁棒性。
- 语义清晰的变量命名:minIndex 直观表达“当前所选星期在星期序列中的最小位置”,避免 maxIndex 等易引发误解的名称。
- 时间复杂度可控:虽为 O(n²)(双层遍历),但因 n 通常为日期样本量(如数百至数千),且内层仅字符串比较,实际性能完全可接受;若需进一步优化,可改用 Map<String, Integer> 先统频次再遍历 weekOrder 查找首个最大值(O(n)),但本题强调逻辑清晰性与教学性,保留直观双循环结构。
⚠️ 注意事项:
- 确保 dayOfWeek(SimpleDate) 方法严格返回上述 7 个标准缩写之一(大小写敏感),否则 weekOrder.indexOf() 将返回 -1,导致逻辑异常。建议在 dayOfWeek 返回前添加断言或日志校验。
- 星期顺序必须与业务定义一致。本例采用公历通用顺序(Sun 为首日),若系统要求 Mon 为每周第一天(如 ISO 8601),则需调整 weekOrder 为 Arrays.asList("Mon", "Tue", ..., "Sun")。
- 此方案不依赖 Calendar 或第三方库,纯 Java SE 实现,兼容 JDK 5+。
综上,通过引入有序参考列表 + 整数索引比较,我们以极简方式优雅解决了“频次并列时择优”这一典型需求。其思想可泛化至任何具有自定义优先级的 Top-K 选取场景。










