【力扣时间】【1154】【简单】一年中的第几天

一年中的第几天

今天的题,有些一言难尽啊……

1、看看题

我是题
题目写得挺详细的,给的case也挺好,照顾到了一些特殊情况。

2、审题

看完题目,各位应该都会会心一笑。
啊?就这就这?

到底是简单题嘛

题目没有藏什么陷阱。如果有,也只能说是和我们生活息息相关的一些常识问题——闰年。
作为格里高利历中特殊的一个年份,我们都知道闰年时,2月会出现第29天。而这也是题目唯一的烟雾弹了。

看看重点:

  1. 输入是一串字符串,题目保证了其正确性和格式(YYYY-MM-DD)。
  2. 输出的是该日期在当年中的天数,第一天则返回1。
  3. 注意闰年的2月份会多一天。

这题的重点几乎都在闰年的判断上了,我本来是这么认为的……

3、思路

很明显,今天的题目有两个点需要解决:

  1. 解析输入的字符串。
  2. 闰年的判断。

相信各位使用java语言开发的社畜,多少都有在业务中接触过日期字符串转换的需求。
我比较常用的是apache common包提供的StringUtils工具类,简单又刺激。
但是leetcode明显不会让我们用这些第三方的包……

总之,关于问题1,我们还有很多土办法。
由于题目保证了字符串的正确性,我们直接通过“-”拆分字符串,并将各个部分转型为int即可。
问题2的话,就属于常识问题了(不懂可以百度 ),4的整数倍但不是100的整数倍,或为400的整数倍的年份,即为闰年。

开工!

4、撸代码

class Solution {

    public int dayOfYear(String date) {
        String[] seg = date.split("-");
        List<Integer> info = Arrays.stream(seg).map(Integer::parseInt).collect(Collectors.toList());
        Calendar calendar = new GregorianCalendar(info.get(0), info.get(1) - 1, info.get(2));
        return calendar.get(Calendar.DAY_OF_YEAR);
    }
}

这是我满心欢喜地写完的第一版,使用Calendar 和其子类,能够帮我我们解决日期相关的几乎所有问题。
但是……丫的leetcode居然不支持使用Calendar !
【力扣时间】【1154】【简单】一年中的第几天
你们用的到底是什么版本的jdk!高等语言的便利的工具类居然都不让用!不过用了还写什么算法啊.

没办法,改改吧……

class Solution {

    public int dayOfYear(String date) {
        List<Integer> seg = Arrays.stream(date.split("-")).map(Integer::parseInt).collect(Collectors.toList());
        //获取年月日
        int year = seg.get(0);
        int month = seg.get(1);
        int day = seg.get(2);

        //初始化每月的第一天所在的当年的第几天
        int[] dayOfMonth = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        int[] daysOfMonth = new int[12];
        daysOfMonth[0] = 0;
        for (int i = 1; i < 12; i++) {
            daysOfMonth[i] = daysOfMonth[i - 1] + dayOfMonth[i - 1];
        }

        //注意闰年时2月要+1天
        return day + daysOfMonth[month - 1] + (month > 2 && isLeapYear(year) ? 1 : 0);
    }

    /**
     * 判断闰年的条件:
     * 为400的整数倍,或为4但不为100的整数倍
     *
     * @param year 年份
     * @return 是否为闰年
     */
    private boolean isLeapYear(int year) {
        return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
    }
}

于是,就出现了第二版土法子……

5、解读

isLeapYear()方法用来判断年份是否为闰年。
判断逻辑也正如上面提到的:400的整数倍 或 4的整数倍但不为100的整数倍。

private boolean isLeapYear(int year) {
        return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
    }

主函数中,我通过spilt拆分字符串,并将各个部分转型为int,这种写法有写耗时,但懒得改了。

List<Integer> seg = Arrays.stream(date.split("-")).map(Integer::parseInt).collect(Collectors.toList());
        //获取年月日
        int year = seg.get(0);
        int month = seg.get(1);
        int day = seg.get(2);

之后的步骤正如注释所说,是为了计算每月的第一天在当年是第几天。这里运用到了一点前缀和的思想。这样,我们只用知道日期所在的月份,就能快速得到该月的第一天在该年是第几天,加上日期就能得到最终答案。

		//初始化每月的第一天所在的当年的第几天
		int[] dayOfMonth = new int[]{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        int[] daysOfMonth = new int[12];
        daysOfMonth[0] = 0;
        for (int i = 1; i < 12; i++) {
            daysOfMonth[i] = daysOfMonth[i - 1] + dayOfMonth[i - 1];
        }

当然,也不要忘了闰年这个特殊情况。

//注意闰年时2月要+1天
return day + daysOfMonth[month - 1] + (month > 2 && isLeapYear(year) ? 1 : 0);

6、提交

【力扣时间】【1154】【简单】一年中的第几天
时间排名惊人地低,但懒得优化了。
毕竟思路如此,我也能接受了。

7、咀嚼

时间复杂度和空间复杂度都是O(1),这应该没什么好说的。

8、偷知识可不算偷

鲸了!不能用Calendar但居然能用LocalDate
这样真的能做到一句话写完了:

public int dayOfYear(String date) {
        return LocalDate.parse(date).getDayOfYear();
    }

以上,都是在题解里看到的其他大牛的解放。
除了依赖官方api的,其他的做法都大同小异

但还是分享一下其他大牛的以供参考

9、总结

总的收获不多,但善于使用各种语言丰富的api,会让你的算法简单很多。
除此之外,就算不用亲自实现,也请牢记各种思路,以备不时之需。
只是这样还算是写算法吗?

简单题,简单地做。
祝大家冬至愉快,记得吃饺子哦。

【力扣时间】【1154】【简单】一年中的第几天

上一篇:Linux下ThinkPHP网站目录权限设置


下一篇:ThinkPHP学习(二)理清ThinkPHP的目录结构及访问规则,创建第一个控制器