Ⅰ、求1+2+3……+n
描述如下:
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
数据范围: 0<<n≤200
进阶: 空间复杂度 )O(1) ,时间复杂度 O(n)
单看题目会十分的简单,但是这道题目是有要求的!!不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
思路:我们前面已经知道:一个对象在创建的时候,会自动的去调用它的默认构造函数,那么我们可以创建一个专门用来求和的类,然后在解决类里面创建n个求和类对象,那么就可以调用n次求和构造函数,是不是就可以很好的解决?
但是呢,这里有个问题就是,我们每次加上的数都比上一个数大,就是会用到上一次的结果,所以我们可以借助静态成员变量,在类中声明,为什么不能用普通的成员变量呢?就是因为对象里面存的自己的成员变量,n次调用的话,并不是同一个增量,而静态成员变量是属于整个类的,不属于任何一个对象,这就保证n次调用,改变的都是同一个增量!!
核心思路就两点:
①充分利用C++特性,构造对象构造函数会自动调用的特点,让求和在构造函数中进行完成
②由于所有对象要针对相同的和进行更新,所以其成员定义为static
class Sum
{
public:
Sum()
{
_sum+=_i;
_i++;
}
static int GetSum()
{
return _sum;
}
private:
static int _i;
static int _sum;
};
int Sum::_i=1;
int Sum::_sum=0;
class Solution {
public:
int Sum_Solution(int n) {
Sum a[n];//C99支持变长数组,这里也可以使用new来开空间
return Sum::GetSum();
}
};
当然了,还有一种写法就是将Sum类写在Solution里面,把它当作内部类,这样可以利用内部类天生就是外部类的友元类这一特性,去访问外部类的私有成员
class Solution {
public:
class Sum
{
public:
Sum()
{
_sum+=_i;
_i++;
}
};
int Sum_Solution(int n) {
Sum a[n];
return _sum;
}
private:
static int _i;
static int _sum;
};
int Solution::_i=1;
int Solution::_sum=0;
这样的写法就少写了静态成员函数去获取静态成员变量这一步骤,当然了,你也可以把静态成员变量的权限设置为公有,这样你也可以不用写静态成员函数!
Ⅱ、日期累加
描述:
设计一个程序能计算一个日期加上若干天后是什么日期。
输入描述:
输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。
输出描述:
输出m行,每行按yyyy-mm-dd的个数输出。
示例:
输入:20110412
20110422
输出:11
思路:大体思路就是,先将天数加到“日”上,判断是否符合大于月份的天数,如果大于,那就月向上加;如果加到当月份大于12时,那就年份向上加,如此循环就能够解决问题!特别注意闰年的情况!
#include <iostream>
using namespace std;
bool IsLeapYear(int year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
int m, n, year, month, day;
cin >> m;
int i = 0;
int monthday[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//13是为了和月份对象
while (i < m)
{
cin >> year >> month >> day >> n;
if (IsLeapYear(year))
{
monthday[2] = 29;//判断闰年
}
//先把天数加上
day += n;
while (day > monthday[month])
{
day -= monthday[month];
month++;
if (month == 13)
{
year++;
month = 1;
if (IsLeapYear(year))
{
monthday[2] = 29;
}
else
{
monthday[2] = 28;
}
}
}
printf("%d-%02d-%02d\n", year, month, day);
++i;
}
return 0;
}
Ⅲ、日期差值
描述
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天。
输入描述:
有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD
输出描述:
每组数据输出一行,即日期差值
示例:
输入:
20110412
20110422
输出:11
思路一:比较两个日期的大小,找出大的日期,循环让大的日期减到和小的日期的年月相同为止,这就可以得到年相差的天数;然后在得到的天数上加上“日”相差的天数,最后还要注意题目说的:两个日期是连续的我们规定他们之间的天数为两天。说明要在结果上在加1才是最终结果
int GetMonthDay(int year, int month)//获取每月的天数
{
int monthday[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))
{
return 29;
}
return monthday[month];
}
bool Max(int y1, int m1, int d1, int y2, int m2, int d2)//找最大日期
{
if (y1 > y2)
{
return true;
}
else if (y1 == y2)
{
if (m1 > m2)
{
return true;
}
else if (m1 == m2)
{
if (d1 > d2)
{
return true;
}
}
}
return false;
}
void Swap(int& x, int& y)//保证第一个日期是大的
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int year1, month1, day1, year2, month2, day2;
while (scanf("%04d%02d%02d\n%04d%02d%02d", &year1, &month1, &day1, &year2, &month2, &day2) != EOF)
{
//比较两个日期的大小,保证第一个日期最大
if (!Max(year1, month1, day1, year2, month2, day2))
{
Swap(year1, year2);
Swap(month1, month2);
Swap(day1, day2);
}
int sum = 0;//记录差值
while (!((year1 == year2) && (month1 == month2)))//大的减到与小的相同为止,记录年相差的天数
{
month1--;
if (month1 == 0)
{
month1 = 12;
year1--;
}
sum += GetMonthDay(year1, month1);//大的和小的年月相差的天数
}
int d = day1 - day2; //日之间的差值
sum += d;//日累加到年差值上
sum++;//最后结果在加1
cout << sum << endl;
}
return 0;
}
思路二:①分别求出每个日期与0000年0月1日相差的天数。②再用两个距离天数相减就可以!③最后结果再加1
#include <iostream>
using namespace std;
//平年从1月到n月的天数
int mon[12]={0,31,59,90,120,151,181,212,243,273,304,334};
//给出年月日,计算距离0000年0月1日的天数和
int CountDay(int y,int m,int d)
{
// 计算0-y年的天数
int yearDay = y*365+y/4-y/100+y/400;//这里面就包含闰年的天数
// 计算到0-m月的天数
int monthDay = mon[m-1];
if(m > 2 && ((y%4 == 0 && y%100 != 0) || y%400==0))//闰年
monthDay += 1;
return yearDay + monthDay + d;
}
int main()
{
int year1,month1,day1;
scanf("%4d%2d%2d",&year1,&month1,&day1);
int n1 = CountDay(year1,month1,day1);
int year2,month2,day2;
scanf("%4d%2d%2d",&year2,&month2,&day2);
int n2 = CountDay(year2,month2,day2);
cout<<abs(n1-n2)+1<<endl;
}
Ⅳ、计算日期到天数的转化
描述
根据输入的日期,计算是这一年的第几天。保证年份为4位数且日期合法。
进阶:时间复杂度:O(n) ,空间复杂度: O(1)
输入描述:
输入一行,每行空格分割,分别是年,月,日
输出描述:
输出是这一年的第几天
示例:
输入:2012 12 31
输出:366
思路:可先用一个数组将天数先存起来(可以先按照平年计算),然后再判断日期是否为3月以上,因为只有这时才需要去判断是否为闰年,如果是3月以上并且是闰年,那需要在总天数上加1即可!
#include <iostream>
using namespace std;
int main()
{
int year,month,day;
cin>>year>>month>>day;
int dayarr[13]={0,31,59,90,120,151,181,212,243,273,304,334,365};//平年
int totalday=dayarr[month-1]+day;//总天数
//下标-1可以这样理解:比如现在是二月1日,那是一年的第几天?,肯定是前面1月的总天数
//所以下面需要判断是否是3月及以上,才需要判断是否为闰年
if((month>2)&&((year%4==0&&year%100!=0)||year%400==0))
{
totalday+=1;
}
cout<<totalday<<endl;
}
Ⅴ、打印日期
描述
给出年分m和一年中的第n天,算出第n天是几月几号。
输入描述:
输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。
输出描述:
可能有多组测试数据,对于每组数据, 按 yyyy-mm-dd的格式将输入中对应的日期打印出来。
示例:
输入:
2000 3
2000 31
2000 40
2000 60
2000 61
2001 60
输出:
2000-01-03
2000-01-31
2000-02-09
2000-02-29
2000-03-01
2001-03-01
思路:相对简单,只需要去判断输入的天数是否符号当前月的天数即可,如果大于,那就月向上加!有点像上面日期累加!
#include <iostream>
using namespace std;
int main()
{
int year, day, month;
int monthday[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };//先算平年
while (cin >> year >> day)
{
int month = 1;
if ((year%4==0 && year%100!=0)||(year%400==0))
{
monthday[2] +=1 ;//闰年2月加上1
}
//判断输入的天数是否符合当前月的天数,大于就月向上加
while (day > monthday[month])
{
day -= monthday[month];
month++;
}
printf("%d-%02d-%02d\n", year, month, day);
}
return 0;
}
小贴士:上面的题目大家可以点击!!