题目一:求1+2+3+…+n
题目描述:
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
示例:
输入:5
返回值:15
分析:
若是只看题目不管要求,这是一道非常简单的题目,我们有好几种方式可以得出最终结果,但加上题目限制条件,可能大多数博友都懵了。
我们来捋一捋:
1、不能使用乘除法,等差数列求和公式不能用了。
2、不能使用for、while,循环求解不能用了。
3、不能使用switch、case和A?B:C,递归求解也不能用了。
思路:
这道题用常规的方式确实解决不了,因为题目把我们要用到的东西都限制死了。解决这道题之前我们需要知道:当一个对象被创建的时候,该对象会自动调用其默认构造函数。
我们需要计算的是1-n这n个数的和,那么我们可以创建n个类对象,这样就可以调用n次构造函数,这就相当于代替了递归。每次需要被加的数都比上一次被加的数大一,我们可以借助于类的静态成员变量,在构造函数中设置该静态成员变量自增即可实现。特别注意,这里必须是静态成员变量,不能是普通的成员变量,因为每个对象被创建时都有属于自己的普通成员变量,而静态成员变量是属于整个类的,这样才能使得这n次调用构造函数时自增的是同一个变量,每个对象访问到的静态成员变量是同一个。同理,存储累加结果的变量也必须是静态成员变量。
代码:
class Add
{
public:
Add() //构造函数
{
_num++;
_ret += _num;
}
static int _num; //静态成员变量,存储正在累加的数字
static int _ret; //静态成员变量,存储1+2+3+...+n的结果
};
//静态成员变量的定义
int Add::_num = 0;
int Add::_ret = 0;
class Solution {
public:
int Sum_Solution(int n) {
//多个测试用例,可能会多次调用,做好初始化工作
//防止第二个测试用例的结果是在第一个测试用例的基础上继续累加得到的
Add::_num = 0;
Add::_ret = 0;
Add* p = new Add[n]; //为n个Add类对象申请空间(可调用n次构造函数)
return Add::_ret; //返回1+2+3+...+n的结果
}
};
代码中为了可以通过类名和类的访问限定符直接突破类域,进而访问到静态成员变量,于是把类的成员变量直接设置为了公有(public)。我们知道,将类的成员变量设置为公有是不安全的,对此,我们可以使用友元类来解决该问题。
代码:
class Add
{
friend class Solution; //声明Solution是Add的有元类
public:
Add() //构造函数
{
_num++;
_ret += _num;
}
private:
static int _num; //静态成员变量,存储正在累加的数字
static int _ret; //静态成员变量,存储1+2+3+...+n的结果
};
//静态成员变量的定义
int Add::_num = 0;
int Add::_ret = 0;
class Solution {
public:
int Sum_Solution(int n) {
//多个测试用例,可能会多次调用,做好初始化工作
//防止第二个测试用例的结果是在第一个测试用例的基础上继续累加得到的
Add::_num = 0;
Add::_ret = 0;
Add* p = new Add[n]; //为n个Add类对象申请空间(可调用n次构造函数)
return Add::_ret; //返回1+2+3+...+n的结果
}
};
代码中我们将Solution声明为Add的友元类,这样Solution类的成员函数就可以访问Add中的非公有成员了。但在某种意义上来说,使用友元是破坏了封装的,使得Solution类的独立性降低了。
实际上,访问类中的静态成员变量最标准的方法是通过静态成员函数,我们可以通过定义静态成员函数来获取静态成员变量,或是对静态成员变量进行修改。
代码:
class Add
{
public:
Add() //构造函数
{
_num++;
_ret += _num;
}
static void Init() //对静态成员变量进行初始化
{
_num = 0;
_ret = 0;
}
static int Getret() //获取静态成员变量_ret
{
return _ret;
}
private:
static int _num; //静态成员变量,存储正在累加的数字
static int _ret; //静态成员变量,存储1+2+3+...+n的结果
};
//静态成员变量的定义
int Add::_num = 0;
int Add::_ret = 0;
class Solution {
public:
int Sum_Solution(int n) {
//多个测试用例,可能会多次调用,做好初始化工作
//防止第二个测试用例的结果是在第一个测试用例的基础上继续累加得到的
Add::Init();
//Add arr[n];
Add* p = new Add[n]; //为n个Add类对象申请空间(可调用n次构造函数)
return Add::Getret(); //返回1+2+3+...+n的结果
}
};
题目二:计算一年的第几天
题目描述:
根据输入的日期计算是这一年的第几天。
示例:
输入:2021 7 18
输出:199
思路:
计算某日期是该年的第几天,也就是计算从该年的1月1日到该日期一共有多少天。计算总天数时,我们可以先按照平年的天数进行计算,这样一来每个月的天数都是固定的,然后再判断所给日期是否为3月及以上,因为此时才需要考虑是否为闰年,若日期为3月及以上并且为闰年,则将之前得到的总天数+1作为最终的总天数。
代码:
#include <iostream>
using namespace std;
int main()
{
int year, month, day;
cin >> year >> month >> day; //输入日期
int daysArray[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; //daysArray[i]表示1月-i月的总天数(默认2月为28天)
int totalDay = daysArray[month - 1] + day; //总天数
if ((month > 2) && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) //如果所给日期为3月及以上,并且该年为闰年
{
totalDay += 1; //总天数+1(2月29日)
}
cout << totalDay << endl; //输出总天数,即该日期为该年的第几天
return 0;
}
题目三:日期差值
题目描述:
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定它们之间的天数为两天。
示例:
输入:19700101
20210718
输出:18827
思路:
根据所给的两个日期,分别得到两个日期的年、月、日,然后分别计算这两个日期年相差的天数、月相差的天数以及日相差的天数(在计算过程中需要注意区分平年和闰年),将它们加起来便是这两个日期的差值,但是题目规定:如果两个日期是连续的,那么题目之间的天数为两天。这意味着我们需要计算的日期差值为闭区间 [date1, date2],所以输出结果时需要再加上1。
代码:
#include <iostream>
using namespace std;
//判断是否为闰年
bool IsLeapYear(int year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
int date1, date2; //存储两个日期
int year1, year2, month1, month2, day1, day2; //存储两个日期的年、月、日
int ret = 0; //存储两个日期的差值
int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //dayArray[i]代表i月的天数(平年)
while (cin >> date1 >> date2) //多组测试数据
{
//确保第一个日期比第二个日期小
if (date1 > date2)
{
int tmp = date1;
date1 = date2;
date2 = tmp;
}
//根据两个日期得到其年、月、日
year1 = date1 / 10000, year2 = date2 / 10000;
day1 = date1 % 100, day2 = date2 % 100;
month1 = date1 % 10000 / 100, month2 = date2 % 10000 / 100;
//计算年相差的天数
for (int year = year1; year < year2; year++)
{
if (IsLeapYear(year))
ret += 366;
else
ret += 365;
}
//计算月相差的天数
for (int month = month1; month < month2; month++)
{
ret += dayArray[month];
if (month == 2 && IsLeapYear(year2))
ret += 1;
}
//计算日相差的天数
for (int day = day1; day < day2; day++)
{
ret++;
}
ret++; //结果为闭区间[date1, date2],所以需要再加1
cout << ret << endl;
}
return 0;
}
题目四:打印日期
题目描述:
给出年份m和一年中的第n天,计算出第n天是几月几号。
示例:
输入:2021 100
输出:2021-04-10
思路:
根据得到的年份判断该年是否为闰年,从而得到该年每月的准确天数。设置月份从1月开始,判断所给总天数是否大于该年该月的总天数,若大于,则将总天数减去该月的总天数后作为新的总天数,然后将月份加一,继续进行判断;若小于,则结束判断,输出日期即可。
代码:
#include <iostream>
using namespace std;
int main()
{
int year, day;
int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //dayArray[i]代表i月的天数(平年)
while (cin >> year >> day) //多组测试数据
{
int month = 1; //month从1月开始
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) //判断该年是否为闰年
dayArray[2] += 1; //闰年2月为29天
//使日期合法
while (day > dayArray[month])
{
day -= dayArray[month];
month++;
}
printf("%d-%02d-%02d\n", year, month, day); //按格式输出
}
return 0;
}
题目五:日期累加
题目描述:
设计一共程序能计算一个日期加上若干天后是什么日期。
输入描述:
输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。
输出描述:
输出m行每行按yyyy-mm-dd的格式输出。
示例:
输入:2
2021 7 18 100
2021 1 1 100
输出:2021-10-26
2021-04-11
#include <iostream>
using namespace std;
//判断是否为闰年
bool IsLeapYear(int year)
{
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
int main()
{
int m, year, month, day, n;
int dayArray[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; //dayArray[i]代表i月的天数(平年)
cin >> m; //读取样例个数
for (int i = 0; i < m; i++)
{
cin >> year >> month >> day >> n; //读取年、月、日和需要累加的天数
if (IsLeapYear(year))
dayArray[2] = 29; //闰年2月设置为29天
day += n; //先将需要累加的天数加到“日”上
//使日期合法
while (day > dayArray[month])
{
day -= dayArray[month];
month++;
if (month == 13) //“年”需要进位
{
year++;
month = 1;
//判断新的一年是否为闰年
if (IsLeapYear(year))
dayArray[2] = 29; //闰年2月设置为29天
else
dayArray[2] = 28; //平年2月设置为28天
}
}
printf("%d-%02d-%02d\n", year, month, day); //按格式输出
}
return 0;
}