前言
针对晴问算法网站第三章的题目所做的题解
3. 入门篇(1)——入门模拟
3.1简单模拟
3.1.1:3N+1猜想
思路:使n==1作为while循环的结束条件;while循环内用if语句对n进行奇偶判断 ,再执行相应的操作;奇偶判断方法:n%2;
#include <iostream>
using namespace std;
int main(){
int n, steps = 0;
cin>>n;
while(n!=1){
if(n%2==0)
n = n/2;
else
n=(3*n+1)/2;
steps++;
}
cout<<steps;
return 0;
}
3.1.2:判断三角形
思路:使用if语句+逻辑与运算执行题目中的三个条件;
#include <iostream>
using namespace std;
int main(){
int A, B, C;
cin>>A>>B>>C;
if(A+B>C && A+C>B && B+C>A)
cout<<"YES";
else
cout<<"NO";
return 0;
}
3.1.3:单调递增序列
思路:使用变量n和vector v接受输入的数据;设置标志flag=1,for循环遍历vector,如果发现一例前者大于后者的情况,则flag置位0;
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, a;
bool flag = 1;
vector<int> v;
cin>>n;
for(int i = 0;i < n-1;i++){
cin>>a;
v.push_back(a);
}
for(int i = 0;i < v.size()-1;i++){
if(v[i]>v[i+1])
flag = 0;
}
if(flag)
cout<<"YES";
else
cout<<"NO";
return 0;
}
3.1.4:数列奇数和
思路:for循环遍历输入的数据,并进行奇偶判断,若为奇数则相加;
#include <iostream>
using namespace std;
int main(){
int n, a, sum = 0;
cin>>n;
for(int i = 0;i < n;i++){
cin>>a;
if(a%2!=0)
sum+=a;
}
cout<<sum;
return 0;
}
3.1.5:三位数
思路:将整数作为字符串输入,for循环遍历字符串;‘n’ - ‘0’ == n;
#include <iostream>
#include <string>
using namespace std;
int main(){
string n;
cin>>n;
for(int i = 0;i < n.length();i++){
cout<<n[i] - '0';
if(i+1 != n.length())
cout<<" ";
}
return 0;
}
3.1.6:水仙花数
思路:将整数作为字符串输入,for循环遍历字符串;‘n’ - ‘0’ == n;求幂pow(base,index);字符串转整数stoi(string);
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
int main(){
string n;
int sum = 0;
cin>>n;
for(int i = 0;i < n.length();i++){
sum+=pow(n[i] - '0',3);
}
if(stoi(n) == sum)
cout<<"YES";
else
cout<<"NO";
return 0;
}
3.1.7:水仙花数II
思路:for循环遍历区间[a,b]内的所有数,将符合水仙花数的放入vector v中,若vector为空则输出NO,否则输出各个元素;
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
int main(){
string a, b;
vector<int> v;
cin>>a>>b;
for(int i = stoi(a);i < stoi(b)+1;i++){
int sum = 0;
for(int j = 0;j < 3;j++){
sum+=pow(to_string(i)[j] - '0',3);
}
if(i == sum)
v.push_back(i);
}
if(v.size() != 0){
for(int i = 0;i < v.size();i++){
cout<<v[i];
if(i+1 != v.size())
cout<<" ";
}
}
else
cout<<"NO";
return 0;
}
3.1.8:2的幂
思路:输入参数为指数且最高为128,由于2^128数量很大,超出了类型表示的范围,故不能先求幂再求余,应根据公式(a * b)%1007 = ((a%1007) * (b%1007))%1007化简为(2 * 2 * 2…)%1007 = ((2%1007) * (2%1007) * …)%1007计算
#include <iostream>
using namespace std;
int main(){
int n, result = 2;
cin>>n;
for(int i = 0;i < n-1;i++){
result = (result%1007)*2;
}
cout<<result%1007;
return 0;
}
3.2查找元素
3.2.1:查找元素
思路:将输入序列放入vector v中,for循环遍历查找;
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, a, x, index, flag = false;
vector<int> v;
cin>>n;
for(int i = 0;i < n;i++){
cin>>a;
v.push_back(a);
}
cin>>x;
for(int i = 0;i < v.size();i++){
if(v[i] == x){
flag = true;
index = i+1;
break;
}
}
if(flag)
cout<<index;
else
cout<<"NO";
return 0;
}
3.2.2:统计元素个数
思路:将输入序列放入vector v中,for循环遍历查找,计算出现次数;
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, a, x, count = 0;
vector<int> v;
cin>>n;
for(int i = 0;i < n;i++){
cin>>a;
v.push_back(a);
}
cin>>x;
for(int i = 0;i < v.size();i++){
if(v[i] == x)
count++;
}
cout<<count;
return 0;
}
3.2.3:寻找元素对
思路:将输入序列放入vector v中,两层for循环遍历,其中内层索引 j 只访问外层 索引i 之后的元素,避免重复计算次数;
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, a, x, count = 0;
vector<int> v;
cin>>n;
for(int i = 0;i < n;i++){
cin>>a;
v.push_back(a);
}
cin>>x;
for(int i = 0;i < v.size()-1;i++){
for(int j = i+1;j < v.size();j++){
if(v[i]+v[j]==x)
count++;
}
}
cout<<count;
return 0;
}
3.3图形输出
3.3.1:等腰直角三角形
思路:两层for循环,外层 i 为行数,内层 j 为列数;根据要求可知每行的列数 j 均不超过当前行数 i ,所以内层for循环的条件应为 j <= i ;
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
for(int i = 0;i < n;i++){
for(int j = 0;j <= i;j++){
cout<<"*";
}
cout<<endl;
}
return 0;
}
3.3.2:等腰直角三角形II
思路:空心三角形的输出可分为三部分,首行输出一个 * ,尾行行输出n个 * ,中间的n-2行使用两层for循环来处理,重点在于在内层for循环用if条件语句判断 i 与 j 的关系,决定是输出 * 还是空格;
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
cout<<"*"<<endl;
for(int i = 0;i < n-2;i++){
cout<<"*";
for(int j = 0;j <= i;j++){
if(j==i)
cout<<"*";
else
cout<<" ";
}
cout<<endl;
}
for(int i = 0;i < n;i++){
cout<<"*";
}
return 0;
}
3.3.3:画X
思路:对于两层for循环来说,循环次数若都为n的话输出为一个矩形,而题目要求每行最后一个 * 后为换行,* 前 非X位置为空格,所以需要在for循环内部加if条件语句控制输出内容;a和b为两个递增和递减的索引,控制是否输出 * ;flag标志含义为在每行是否已输出两个 * ,决定是否结束本行,进入下一行;X的中点由 a==n/2控制;
#include <iostream>
using namespace std;
int main(){
int n;
cin>>n;
int a = 0, b = n-1, flag = 0;
for(int i = 0;i < n;i++){
for(int j = 0;j < n;j++){
if(a == j || b == j){
cout<<"*";
flag++;
if(a == n/2 || flag == 2)
break;
}
else
cout<<" ";
}
flag = 0;
a++;
b--;
cout<<endl;
}
return 0;
}
3.4日期处理
3.4.1:判断闰年
思路:判断闰年的方法:如果年份是400的倍数,或者是4的倍数但不是100的倍数,那么称这个年份为闰年;
#include <iostream>
using namespace std;
bool isLeapYear(int year){
return (year%400 == 0)||(year%4 == 0 && year%100 != 0);
}
int main(){
int n;
cin>>n;
if(isLeapYear(n))
cout<<"YES";
else
cout<<"NO";
return 0;
}
3.4.2:日期加法
思路:输入的天数n作为for循环的次数,每循环一次在日期上增加一天,在循环内部用if条件语句做好month和year的判断处理;
#include <cstdio>
using namespace std;
struct Date{
int year, month, day;
};
int days[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool isLeapYear(int year){
return (year%400 == 0)||(year%4 == 0 && year%100 != 0);
}
void addDays(Date &date, int n){
for(int i = 0;i < n;i++){
date.day++;
if(date.day-1 == days[isLeapYear(date.year)][date.month]){
date.day = 1;
date.month++;
if(date.month-1 == 12){
date.month = 1;
date.year++;
}
}
}
}
int main(){
Date date;
int n;
scanf("%d-%d-%d",&date.year ,&date.month ,&date.day);
scanf("%d",&n);
addDays(date, n);
printf("%04d-%02d-%02d",date.year ,date.month ,date.day);
return 0;
}
3.4.3:日期减法
思路:输入的天数n作为for循环的次数,每循环一次在日期上减去一天,在循环内部用if条件语句做好month和year的判断处理;
#include <cstdio>
using namespace std;
struct Date{
int year, month, day;
};
int days[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool isLeapYear(int year){
return (year%400 == 0)||(year%4 == 0 && year%100 != 0);
}
void subDays(Date &date, int n){
for(int i = 0;i < n;i++){
date.day--;
if(date.day == 0){
date.month--;
if(date.month == 0){
date.month = 12;
date.year--;
}
date.day = days[isLeapYear(date.year)][date.month];
}
}
}
int main(){
Date date;
int n;
scanf("%d-%d-%d",&date.year ,&date.month ,&date.day);
scanf("%d",&n);
subDays(date, n);
printf("%04d-%02d-%02d",date.year ,date.month ,date.day);
return 0;
}
3.4.4:一年中的第几天
思路:将日期分为三部分处理,对year的处理主要是判断是平年还是闰年;month作为for循环的判断条件,将1~month-1的天数加起来;最后再加上day就可以了;
#include <cstdio>
using namespace std;
struct Date{
int year, month, day;
};
int days[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool isLeapYear(int year){
return (year%400 == 0)||(year%4 == 0 && year%100 != 0);
}
int main(){
Date date;
int sum = 0;
scanf("%d-%d-%d",&date.year ,&date.month ,&date.day);
for(int i = 1;i < date.month;i++){
sum += days[isLeapYear(date.year)][i];
}
printf("%d",sum+date.day);
return 0;
}
3.4.5:日期先后
思路:按照year,month,day的顺序判断日期先后;
#include <cstdio>
using namespace std;
struct Date{
int year, month, day;
};
int days[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool isLeapYear(int year){
return (year%400 == 0)||(year%4 == 0 && year%100 != 0);
}
bool isBefore(Date date1, Date date2){
if(date1.year != date2.year)
return date1.year < date2.year;
if(date1.month != date2.month)
return date1.month < date2.month;
return date1.day < date2.day;
}
int main(){
Date date1;
Date date2;
scanf("%d-%d-%d",&date1.year ,&date1.month ,&date1.day);
scanf("%d-%d-%d",&date2.year ,&date2.month ,&date2.day);
if(isBefore(date1, date2))
printf("YES");
else
printf("NO");
return 0;
}
3.4.6:周几
思路:计算输入的日期与函数内一个定好的日期(周日)的天数差;对7取余输出;x%7 的值只可能为0-6;
#include <cstdio>
using namespace std;
struct Date{
int year, month, day;
};
int days[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};
bool isLeapYear(int year){
return (year%400 == 0)||(year%4 == 0 && year%100 != 0);
}
bool isBefore(Date date1, Date date2){
if(date1.year != date2.year)
return date1.year < date2.year;
if(date1.month != date2.month)
return date1.month < date2.month;
return date1.day < date2.day;
}
int dayDiffer(Date date1, Date date2){
int steps = 0;
while(isBefore(date1, date2)){
date1.day++;
if(date1.day-1 == days[isLeapYear(date1.year)][date1.month]){
date1.day = 1;
date1.month++;
if(date1.month-1 == 12){
date1.month = 1;
date1.year++;
}
}
steps++;
}
return steps;
}
int main(){
Date date_comp = {2022,06,26};
Date date;
int differ = 0;
scanf("%d-%d-%d",&date.year ,&date.month ,&date.day);
if(isBefore(date,date_comp))
printf("%d",dayDiffer(date, date_comp)%7?7-(dayDiffer(date, date_comp)%7):dayDiffer(date, date_comp)%7);
else
printf("%d",dayDiffer(date_comp, date)%7);
return 0;
}
3.5进制转换
3.5.1:十进制转二进制
思路:除基取余法;用do while循环的原因是:对入口参数特殊值0的处理;
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n;
vector<int> v;
cin>>n;
do{
v.push_back(n%2);
n/=2;
}while(n!=0);
for(int i = v.size()-1;i > -1;i--)
cout<<v[i];
return 0;
}
3.5.2:二进制转十进制
思路:取出输入参数的每一位,并乘上对应的2^(n-1),相加即可
#include <iostream>
#include <string>
using namespace std;
int main(){
string n;
int dec = 0, index = 1;
cin>>n;
for(int i = n.size()-1;i > -1;i--){
dec += (n[i]-'0')*index;
index *= 2;
}
cout<<dec;
return 0;
}
3.5.3:十进制转K进制
思路:除基取余法;用do while循环的原因是:对入口参数特殊值0的处理;考虑到16进制的情况,把10-15换成A-F输出;
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n, k;
vector<int> v;
cin>>n>>k;
do{
v.push_back(n%k);
n/=k;
}while(n!=0);
for(int i = v.size()-1;i > -1;i--){
if(v[i]>9)
cout.put(v[i]-10+'A');
else
cout<<v[i];
}
return 0;
}
3.5.4:K进制转十进制
思路:取出输入参数的每一位,并乘上对应的k^(n-1),相加即可;考虑到16进制的情况,把A-F换成10-15计算;
#include <iostream>
#include <string>
using namespace std;
int main(){
string n;
int k;
int dec = 0, index = 1;
cin>>n>>k;
for(int i = n.size()-1;i > -1;i--){
if(n[i]-55>9)
dec += (n[i]-55)*index;
else
dec += (n[i]-'0')*index;
index *= k;
}
cout<<dec;
return 0;
}
3.6字符串处理
3.6.1:回文串
思路:for循环遍历一半的字符串,控制索引比较首尾;i和s.length()-1-i;
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
bool flag = true;
cin>>s;
for(int i = 0;i < s.length()/2;i++){
if(s[i] != s[s.length()-1-i])
flag = 0;
}
if(flag)
cout<<"YES";
else
cout<<"NO";
return 0;
}
3.6.2:单词倒序
思路:将单词按输入顺序存入vector v中,for循环倒序遍历输出;
#include <iostream>
#include <vector>
using namespace std;
int main(){
string s;
vector<string> v;
while(cin>>s)
v.push_back(s);
for(int i = 0;i < v.size();i++){
cout<<v[v.size()-1-i];
if(i+1 != v.size())
cout<<" ";
}
return 0;
}
3.6.3:单词倒序II
思路:将单词按输入顺序存入vector v中,使用双重for循环遍历输出,外层for循环选定单词,内层for循环将单词倒序;
#include <iostream>
#include <vector>
using namespace std;
int main(){
string s;
vector<string> v;
while(cin>>s)
v.push_back(s);
for(int i = 0;i < v.size();i++){
for(int j = 0;j < v[i].length();j++){
cout<<v[i][v[i].length()-1-j];
}
if(i+1 != v.size())
cout<<" ";
}
return 0;
}
3.6.4:单词数
思路:设置一个变量count初始值为0作为计数器,将cin>>s放入while()循环作为条件,当没有单词输入时,会跳出循环;
#include <iostream>
using namespace std;
int main(){
string s;
int count = 0;
while(cin>>s)
count++;
cout<<count;
return 0;
}
3.6.5:首字母大写
思路:将单词按输入顺序存入vector v中,使用for循环遍历每个单词,访问首字母完成替换;
#include <iostream>
#include <vector>
using namespace std;
int main(){
string s;
vector<string> v;
while(cin>>s)
v.push_back(s);
for(int i = 0;i < v.size();i++){
v[i][0] = v[i][0] + ('A'-'a');
cout<<v[i];
if(i+1 != v.size())
cout<<" ";
}
return 0;
}
3.6.6:公共前缀
思路:将输入的字符串依次存入vector v中,并且统计出最小的长度(min_length);双重for循环遍历v,外层决定遍历字符串,内层决定遍历字符串的字符,且内层次数由min_length决定;以第一个字符串为基,与后续字符串依次比较,得出最短的公共长度(common_length),输出第一个字符串common_length长度的字符;
#include <iostream>
#include <vector>
using namespace std;
int main(){
string s;
int n, min_length = 51, common_length = 51;
vector<string> v;
cin>>n;
for(int i = 0;i < n;i++){
cin>>s;
if(s.length()<min_length)
min_length = s.length();
v.push_back(s);
}
for(int i = 1;i < v.size();i++){
int temp = 0;
for(int j = 0;j < min_length;j++){
if(v[0][j] == v[i][j])
temp++;
else
break;
}
if(temp < common_length)
common_length = temp;
}
for(int i = 0;i < common_length;i++)
cout<<v[0][i];
return 0;
}
3.6.7:连续相同字符统计
思路:for循环遍历输入的字符串,前后字符相同则count++,字符不同则count重新计数,并输出上一个字符的数据;
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
int count = 0;
cin>>s;
for(int i = 0;i < s.length();i++){
count++;
if(s[i]!=s[i+1]){
cout<<s[i]<<" "<<count;
if(i+1 != s.length())
cout<<endl;
count = 0;
}
}
return 0;
}
3.6.8:C语言合法变量名
思路:for循环遍历输入的字符串,根据变量名的规则写出if条件语句判断即可;
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
bool flag = true;
cin>>s;
for(int i = 0;i < s.length();i++){
if(i){
if(('A'<=s[i]&&s[i]<='Z')||('a'<=s[i]&&s[i]<='z')||(s[i]-'0'<=9&&s[i]-'0'>=0)||s[i]=='_')
flag = true;
else{
flag = false;
break;
}
}
else{
if(s[i]-'0'<=9 && s[i]-'0'>=0){
flag = false;
break;
}
}
}
if(flag)
cout<<"YES";
else
cout<<"NO";
return 0;
}