首页 > 解决方案 > 如何计算范围 [a, b] 中的闰年而不在 C# 上使用循环

问题描述

假设您有a年和b年,它们是年份范围(包括在内),如何在不使用循环的情况下正确计算此范围内的闰年?(公历)

我在 C# 上写了这个,但我不认为我的代码很棒。我也使用了一个全局变量,但是大声笑,我认为有一个比这更好、更优雅的解决方案。我只是一个新手,很抱歉我问了这个愚蠢的问题。另外,我认为你不应该在这里使用 DateTime 等等。

这是我的代码:

class Program
{
    public static int leap_years = 0;
    static void Main()
    {
        do
        {
            int a, b;
            leap_years = 0;
            do Console.Write("Enter a: ");
            while (!int.TryParse(Console.ReadLine(), out a) || a < 0);
            do Console.Write("Enter b: ");
            while (!int.TryParse(Console.ReadLine(), out b) || b < 0 || a == b || a >= b);
            Console.WriteLine("Leap years: " + countLeapYears(a, b));
        } while (Console.ReadKey().Key != ConsoleKey.Escape);
    }

countLeapYears在哪里

    static public int countLeapYears(int a, int b)
    {
        if (a > b)
            return leap_years;
        else
        {
            if (a % 4 == 0)
            {
                if (a % 100 == 0)
                {
                    if (a % 400 == 0)
                    {
                        Console.WriteLine("Year {0} - leap year", a);
                        leap_years++;
                        a += 4;
                        countLeapYears(a, b);
                    }
                    else
                    {
                        Console.WriteLine("Year {0} - not a leap year", a);
                        a++;
                        countLeapYears(a, b);
                    }
                }
                else
                {
                    Console.WriteLine("Year {0} - leap year", a);
                    leap_years++;
                    a += 4;
                    countLeapYears(a, b);
                }
            }
            else
            {
                Console.WriteLine("Year {0} - not a leap year", a);
                a++;
                countLeapYears(a, b);
            }
        }
        return leap_years;
    }
}

标签: c#leap-year

解决方案


好吧,我们没有 year 0:1BC后面跟着1ADwhich破坏了乐趣。但是,如果我们只能使用AD(正数年),您可以尝试这样的事情:

private static int countLeapYears(int from, int to) =>
  (to / 4 - (from - 1) / 4) -
  (to / 100 - (from - 1) / 100) +
  (to / 400 - (from - 1) / 400);

让我们就朴素计算来测试它:

private static int naiveCount(int from, int to) {
  int result = 0;

  for (int i = from; i <= to; ++i) 
    if (i % 400 == 0 || i % 4 == 0 && i % 100 != 0)
      result += 1;

  return result;
}

...

Random gen = new Random(123);

var result = Enumerable
  .Range(1, 20)
  .Select(i => {
    int to = gen.Next(1590, 2222);
    int from = gen.Next(1590, 2222);

    return (from: Math.Min(from, to), to: Math.Max(from, to));
  })
  .Select(test => $"{test.from} - {test.to} actual: {countLeapYears(test.from, test.to),3} expected: {naiveCount(test.from, test.to),3}");
  
Console.Write(string.Join(Environment.NewLine, result));

结果:

2163 - 2212 actual:  12 expected:  12
2059 - 2102 actual:  10 expected:  10
1620 - 2056 actual: 107 expected: 107
1600 - 1684 actual:  22 expected:  22
1713 - 1988 actual:  67 expected:  67
1902 - 2164 actual:  65 expected:  65
1709 - 1881 actual:  42 expected:  42
1639 - 2124 actual: 118 expected: 118
1751 - 1948 actual:  48 expected:  48
1594 - 2184 actual: 144 expected: 144
1605 - 1691 actual:  21 expected:  21
1591 - 2082 actual: 120 expected: 120
1993 - 2066 actual:  18 expected:  18
2022 - 2158 actual:  33 expected:  33
1678 - 1919 actual:  57 expected:  57
1966 - 2128 actual:  40 expected:  40
1635 - 2069 actual: 106 expected: 106
1649 - 1963 actual:  75 expected:  75
1719 - 2169 actual: 110 expected: 110
1847 - 2093 actual:  61 expected:  61

推荐阅读