前言——本文代码由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
谢谢各位老板收看,如有错误,请及时帮小弟我指正。