题目描述

✅ 1118. 一月有多少天

题意分析

给定合法的年份 year 和月份 month,返回该年该月的天数。月份从一到十二,只求指定月份的长度,不是从年初累计到该月的天数。

除二月以外,各月份的天数不随年份变化;二月在平年有二十八天,在闰年有二十九天。因此问题由固定月份查表与闰年判定两部分组成。

解法:闰年判断

核心思路

[!blue]

先把平年十二个月的天数放进固定数组。代码在第零项放一个占位零,使月份可以直接作为数组下标,不必在每次查询时做减一转换;合法月份不会读取占位项。

闰年规则包含逐层例外:通常每四年有一个闰年,但能被一百整除的整百年不按这条规则计算;其中能被四百整除的年份又仍然是闰年。所以条件是“能被四百整除”,或者“能被四整除但不能被一百整除”。

第二个分支排除普通整百年,第一个分支保留四百倍数年,二者用逻辑或连接。不能在整条公式之后再统一排除一百的倍数,否则连应当保留的四百倍数也会被排除。

最后只在月份为二月且年份为闰年时返回二十九,其他情况都使用平年表。这样年份修正只影响真正变化的月份,其余月份不需要分支处理。

解题步骤

  1. 创建带零号占位的平年月份天数表。
  2. 按四百倍数,或四的倍数且非一百倍数,计算闰年标记。
  3. 闰年二月返回二十九,否则返回表中该月份的天数。

代码实现

class Solution {
    public int numberOfDays(int year, int month) {
        // 第零项占位,使月份可以直接作为下标。
        int[] days = {
            0,
            31,
            28,
            31,
            30,
            31,
            30,
            31,
            31,
            30,
            31,
            30,
            31
        };
        // 整百年需能被 400 整除,其他年份按 4 的倍数判断。
        boolean leap = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);

        // 只有二月需要根据闰年增加一天。
        if (month == 2 && leap) {
            return 29;
        }

        return days[month];
    }
}
func numberOfDays(year int, month int) int {
    // 第零项占位,使月份可以直接作为下标。
    days := []int{
        0,
        31,
        28,
        31,
        30,
        31,
        30,
        31,
        31,
        30,
        31,
        30,
        31,
    }
    // 整百年需能被 400 整除,其他年份按 4 的倍数判断。
    leap := year%400 == 0 || (year%4 == 0 && year%100 != 0)
    // 只有二月需要根据闰年增加一天。
    if month == 2 && leap {
        return 29
    }
    return days[month]
}

复杂度分析

  • 时间复杂度:$O(1)$,表长度固定,只进行固定次数的取模、判断与一次查表。
  • 空间复杂度:$O(1)$,月份表大小与输入年份无关。

关键点总结

[!green]

  • 月份长度主要由固定表决定,只有二月需要年份修正。
  • 四百倍数是整百年排除规则中的例外,必须作为独立可成立的分支。
  • 月份编号与表下标一致,零号占位不代表真实月份。

易错点总结

[!yellow]

  • 只判断能被四整除,会把普通整百年错误判成闰年。
  • 只排除一百的倍数,却漏掉四百倍数分支,会错误排除一部分真正闰年。
  • 在两个分支求或以后再统一排除整百年,仍会覆盖四百倍数的有效条件。
  • 对所有月份都应用闰年加一天,会改变本应固定的其他月份。
  • 天数表没有零号占位却直接使用月份下标,会让月份整体错位并在年底越界。

相似题目

题目 难度 关联与区别
1154. 一年中的第几天 简单 每月天数和闰年规则是计算年内序号的基础,本题只返回指定月份长度。
1360. 日期之间隔几天 简单 原题计算跨日期的总天数,本题提供月份与闰年的局部日期规则。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2024/15850622
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!