《算法零基础》Day06.日期算法。 楼下大爷看完直呼简单!

前言——本文代码由C语言实现

今天是学习算法的第六天,如果你也有
强烈的欲望想学好算法和数据结构,请跟随他的脚步:
链接: 英雄哪里出来

大家一起学习,一起成长。

关于日期的一些概念

闰年问题

1.每一年都是闰年或者平年,闰年有366天,平年有365天。
2.闰年比平年的2月多1天。

那如何判断是否为闰年?
答:
1.概年份能被4整除且不能被100整除
2.能被400整除。

闰年代码实现

就是把上面两句话翻译成程序

bool Is_Leap_Year(int year)
{
	return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}

题目

Leetcode1185.一周中的第几天

原题链接: 一周中的第几天
给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。

示例:

输入:day = 31, month = 8, year = 2019
输出:"Saturday"

提示:

给出的日期一定是在 1971 到 2100 年之间的有效日期。

分析

题目给出提示,日期是在1971年到2100年,但是要我们返回一个星期几。。
身为老实人,那我只能根据1971年1月1日是周几来判断我要求的结果。

这里我继续要写一个函数,来计算题目给出的日期距离 1971年1月1日 有多少天。

计算总天数的代码与注释

这个函数接收的参数就是题目给出的年月日

int Get_All_Day(int year, int month, int day)
{
	int y = 1971; //开始年份
	int ans = 0; //记录总天数

	//计算每年对应的天数
	for (y; y < year; ++y)
	{
		if (Is_Leap_Year(y)) //根据上面介绍的判断闰年函数
		{
			ans += 366; //如果闰年就加366天
		}
		else
		{
			ans += 365; //平年加365天
		}
	}
	
	//当加到题目给出的这一年时,我们再把月份对应的天数加上
	for (int m = 0; m < month; ++m)
	{
        ans += Day_Of_Month(year, m); 
	}
	
	//再把剩下的天数加上并返回答案
	return (ans + day);
}

这里就有老板要问,那你这个月份对应的天数怎么求?

因为写的是C语言代码,所以我顺便复习复习switch语句和函数。把他封装成一个函数,如下:

//看到函数名就知道函数要干什么
int Day_Of_Month(int year, int month)
{
    switch (month)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			return 31;

		case 4:
		case 6:
		case 9:
		case 11:
			return 30;

		case 2:
		{
			if (Is_Leap_Year(year))
				return 29;
			else
				return 28;	
		}
		    break;
	}
    return 0;
}

一 三 五 七 八 十 腊 是31天;
四 六 九 十一 都是30天;
二月份单独处理

我知道还有更简单更短的代码,但我为人老实,只想到这样的笨比做法,不过应该好理解,大部分人能懂。

总代码

//判断闰年
bool Is_Leap_Year(int year);
//计算这个月有多少天
int Day_Of_Month(int year, int month);
//计算从1971年到现在有多少天
int Get_All_Day(int year, int month, int day);

char* dayOfTheWeek(int day, int month, int year)
{
	//边界条件判断
	if (day <= 0 || day > 31 || month > 12 || month <= 0 || year < 0)
		return NULL;
	
	//获取总天数
	int allday = Get_All_Day(year, month, day);
	
	//对总天数减一并对7取模,就获得想要结果
	int rest_day = (allday - 1) % 7;
	
	//输出对应的星期
	switch (rest_day)
	{
	case 0: return "Friday";
	case 1: return "Saturday"; 
	case 2: return "Sunday"; 
	case 3: return "Monday";
	case 4: return "Tuesday";
	case 5: return "Wednesday";
	case 6: return "Thursday";
	default:
		break;
	}
	return NULL;
}

bool Is_Leap_Year(int year)
{
	return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}

int Day_Of_Month(int year, int month)
{
    switch (month)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			return 31;

		case 4:
		case 6:
		case 9:
		case 11:
			return 30;

		case 2:
		{
			if (Is_Leap_Year(year))
				return 29;
			else
				return 28;	
		}
		    break;
	}
    return 0;
}

int Get_All_Day(int year, int month, int day)
{
	int y = 1971;
	int ans = 0;

	for (y; y < year; ++y)
	{
		if (Is_Leap_Year(y))
		{
			ans += 366;
		}
		else
		{
			ans += 365;
		}
	}

	for (int m = 0; m < month; ++m)
	{
        ans += Day_Of_Month(year, m);
	}

	return (ans + day);
}

运行结果:只能说一般
在这里插入图片描述

LeetCode1154:一年中的第几天

链接: 一年中的第几天

给你一个按 YYYY-MM-DD 格式表示日期的字符串 date,请你计算并返回该日期是当年的第几天。

一看这个题,就明白又要用到我们上面说的那些函数了。

分析

题目给出的是字符串,这样就很难受,所以得想办法把字符串转换成数字,这里也不用什么atoi 什么stoi 了,利用C语言实现一个字符转整型的函数。如下:

这个函数会传进来一个字符指针,并传进来一个要转换的长度
我们用字符串里的字符数字减去字符‘0’,就得到了整型数字。

//看函数名就知道函数要干什么
int Str_To_Int(char* str, int len)
{
    int i = 0, sum = 0;

    for(i = 0; i < len; ++i)
    {
        sum = sum * 10 + (str[i] - '0');
    }
    return sum;
}

总代码

//判断闰年
bool Is_Leap_Year(int year);
//字符转数字
int Str_To_Int(char* str, int len);
//计算这个月有几天
int Day_Of_Month(int year, int month);

int dayOfYear(char* date)
{
	//判空
    if (NULL == date)
    return 0;
	//这里根据题意,转换出对应的整型数字
    int year = Str_To_Int(date, 4);
    int month = Str_To_Int(date + 5, 2);
    int day = Str_To_Int(date + 8, 2);
    int ans = 0;

    for (int i = 1; i < month; ++i)
    {
        ans += Day_Of_Month(year, i);
    }

    return ans + day;
}
//---------------------------
//要用到的函数
bool Is_Leap_Year(int year)
{
    return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}

int Str_To_Int(char* str, int len)
{
    int i = 0, sum = 0;

    for(i = 0; i < len; ++i)
    {
        sum = sum * 10 + (str[i] - '0');
    }
    return sum;
}

int Day_Of_Month(int year, int month)
{
    switch (month)
	{

		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			return 31;

		case 4:
		case 6:
		case 9:
		case 11:
			return 30;

		case 2:
		{
			if (Is_Leap_Year(year))
				return 29;
			else
				return 28;	
		}
		    break;
	}
    return 0;
}

运行结果:
拉跨吗,不拉跨,因为我是老实人做法
在这里插入图片描述

指针问题

有的老板问,为什么你那个字符转整型参数给的是 date + 5, 这是什么意思?

答:因为date是一个指针,指针进行加减操作时,每加或减去1,都是跨越一个对应的类型的字节数
图解:
一格代表一字节
那int类型是四字节,指针加一就是一下加了四个字节
在这里插入图片描述

1360.日期之间相隔几天

原题链接: 日期之间相隔几天

日期以字符串形式给出,格式为 YYYY-MM-DD

分析

太无聊了这个题,和第一题一样方法,我们把上面那个题的代码偷过来 借过来。

老实人做法
题目计算两个日期相隔几天,我不知道哪个日期在前哪个在后,只能找个临界,就是题目给的1971年。然后把两个日期距离1971多少天都算出来,两个一减再求绝对值即可。

代码

//判断闰年
bool Is_Leap_Year(int year);
//字符转数字
int Str_To_Int(char* str, int len);
//计算这个月有多少天
int Day_Of_Month(int year, int month);
//计算总天数
int Get_All_Day(int year, int month, int day);

int daysBetweenDates(char * date1, char * date2)
{
    if (NULL == date1 || NULL == date2)
    return 0;

    int year1 = Str_To_Int(date1, 4);
    int month1 = Str_To_Int(date1 + 5, 2);
    int day1 = Str_To_Int(date1 + 8, 2);

    int year2 = Str_To_Int(date2, 4);
    int month2 = Str_To_Int(date2 + 5, 2);
    int day2 = Str_To_Int(date2 + 8, 2);

    int allday1 = Get_All_Day(year1, month1, day1);
    int allday2 = Get_All_Day(year2, month2, day2);

    return abs(allday2 - allday1);
}
//-------------------------
//需要的函数
bool Is_Leap_Year(int year)
{
    return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
}

int Str_To_Int(char* str, int len)
{
    int i = 0, sum = 0;

    for(i = 0; i < len; ++i)
    {
        sum = sum * 10 + (str[i] - '0');
    }
    return sum;
}

int Day_Of_Month(int year, int month)
{
    switch (month)
	{

		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			return 31;

		case 4:
		case 6:
		case 9:
		case 11:
			return 30;

		case 2:
		{
			if (Is_Leap_Year(year))
				return 29;
			else
				return 28;	
		}
		    break;
	}
    return 0;
}

int Get_All_Day(int year, int month, int day)
{
    int y = 1971;
	int ans = 0;

	for (y; y < year; ++y)
	{
		if (Is_Leap_Year(y))
		{
			ans += 366;
		}
		else
		{
			ans += 365;
		}
	}

     for (int i = 1; i < month; ++i)
    {
        ans += Day_Of_Month(year, i);
    }

    return ans + day;
}

运行结果:
虽然内存消耗多,但是好理解,好用。
在这里插入图片描述

装笔解法——基姆拉尔森计算公式

本公式用来计算指定的年月日是星期几

W = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1) % 7 

注意:
在公式中有个与其他公式不同的地方:
把一月和二月看成是上一年的十三月和十四月。
例:如果是2004-1-10则换算成:2003-13-10来代入公式计算。

end

谢谢各位老板收看,如有错误,请及时帮小弟我指正。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值