題目一:求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;
}