Problem overview
The method IsLeapYear takes an integer year and returns a bool: true for a leap year and false otherwise. Two rules define a leap year:
- A year divisible by 4 is a leap year.
- Exception: a year divisible by 100 (1800, 1900, 2100 and so on) is a leap year only if it is also divisible by 400.
So 2020 and 1968 are leap years, 2021 is not, and 1900 is not, because it is divisible by 100 but not by 400. The year 2000 is a leap year, because it is divisible by 400.
The exceptions exist because a year is slightly shorter than 365.25 days. Adding a day every four years overshoots a little, so the calendar skips the leap day in most century years. Across any 400 consecutive years, there are 100 multiples of 4, of which 4 are multiples of 100 but only 1 is a multiple of 400, so 97 years are leap years. The method only needs the divisibility rules, not the astronomy.
The input is a plain int, and the lesson's tests use ordinary positive years, so there is no need to handle special ranges.
Approach
The rules are nested: the 400 rule overrides the 100 rule, which overrides the 4 rule. The easiest way to code this is to test the most specific rule first and return as soon as a rule decides the answer:
- Divisible by 400: leap year.
- Divisible by 100 (and so not by 400): not a leap year.
- Divisible by 4 (and so not by 100): leap year.
- Anything else: not a leap year.
Because each check returns, a later check only sees the years that the earlier checks didn't settle. That is why the 100 test doesn't need to say "and not divisible by 400".
Step by step
- Check 400 first. A year divisible by 400 is also divisible by 100 and by 4. If the 100 rule came first, the year 2000 would be wrongly rejected. Testing 400 first lets it return
truebefore the century rule can reject it. - Check 100 next. A year that reaches this point is not divisible by 400. If it is divisible by 100, such as 1900, it is not a leap year, so return
false. - Check 4 third. Years that reach this point aren't centuries, so divisibility by 4 decides everything. Return
truefor 2020 or 1968. - Return
false. A year that failed all three checks, such as 2021, isn't divisible by 4.
Tracing a few years through the four checks makes the order concrete:
- 2000: divisible by 400, so the first check returns
true. - 1900:
1900 % 400is 300, so the first check fails.1900 % 100is 0, so the second check returnsfalse. - 2020:
2020 % 400is 20 and2020 % 100is 20, so both checks fail.2020 % 4is 0, so the third check returnstrue. - 2021: all three remainders are non-zero, so the method reaches the final
return false;.
The solution in C#
class Solution {
public bool IsLeapYear(int year) {
if (year % 400 == 0) {
return true;
}
if (year % 100 == 0) {
return false;
}
if (year % 4 == 0) {
return true;
}
return false;
}
}
Some C# details:
- The remainder operator.
year % 400is the remainder after dividing by 400, soyear % 400 == 0means "divides evenly". Don't confuse%with/, which for twointvalues is integer division and drops the fractional part. - Return type
bool. The method returns the keywordstrueandfalse, written in lowercase. When the result is printed, C# displays them asTrueandFalse. - Several returns. A method can return from anywhere. The first
returnthat executes ends the method, so noelsekeywords are needed. - A shorter form. The same rule fits in one expression:
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0). It gives identical answers. The step-by-step version is longer, but each line maps to one rule.
Edge cases and common mistakes
- Century years. 1900 must be
falseand 2000 must betrue. A solution that only tests divisibility by 4 gets 1900 wrong. - Wrong order of checks. If the 100 check runs before the 400 check, 2000 returns
false. The order of the first twoifstatements is what makes the logic right. - Writing
=instead of==. In C#,if (year % 4 = 0)doesn't compile. Comparison uses two equals signs. - Treating 4 as the only rule. The rule "every four years" is only the starting point.
- Forgetting the final return. If the last
return false;is missing, the compiler reports that not all code paths return a value.
Testing
IsLeapYear(2020)givestrue.IsLeapYear(2021)givesfalse.IsLeapYear(1968)givestrue.IsLeapYear(1900)givesfalse.IsLeapYear(2000)givestrue.