第一题
这个题目其实本质上和之前的计算月份的题目区别不是很大,这里主要有个技巧就是,我们只需要知道某一个月的13号是星期几,接下来就是依次增加一个月的天数再对7取余再加一即可得到下一个13号是星期几。
思路有了,具体的算法呢?不妨先从简单的算起,我们先计算1900年的每个月的13号
- 首先是1月13号,这个很显然就是1月1号过去12天嘛,容易计算得出1月13号是星期6
- 接下来是2月13号,因为1月13号到2月13号这中间跨过了一个1月的尾巴嘛,跨过了哪个月的月末,加上去的天数就是那一个月的天数,这样很容易就能发现2月13号对应的星期的序号就是(6+31)%7+1=2,同学们可以自己验证一下,至于为啥,一周7天一个循环嘛,很容易就可以想到取余操作
- 随后的每一个月都是一样的操作,一直到12月
现在我们已经有了1900年的13号对应星期几,那么基于1900年12月13号是星期几计算1901年1月13号该怎么做呢,一样的道理的,按照之前的规则往下迭代即可
#include<iostream>
using namespace std;
int main()
{
int daysCount[7]={0};
int months[12]={31,31,28,31,30,31,30,31,31,30,31,30};//先是12月,再是1月开始
int year=0;
bool needAdd=false;
int currentYear=0;
bool firstRound=true;
int day13=0;
cin >>year;
for(int i=0;i<year;i++)
{
currentYear=1900+i;
needAdd=false;
if((currentYear%400==0)||(currentYear%4==0&¤tYear%100!=0))
{
needAdd=true;
}
for(int j=0;j<12;j++)
{
if(firstRound&&j==0)
{
day13=(day13+12)%7;
firstRound=false;
}
else
{
if (j==2&&needAdd)
{
day13++;
}
day13=(day13+months[j])%7;
}
daysCount[day13]+=1;
}
}
for(int i=0;i<7;i++)
{
cout << daysCount[i]<<" ";
}
return 0;
}
第二题
这个题目首先需要了解的是如何处理输入,这一块可以参考题目中的提示这一部分,这是一个很经典的处理输入的方法,记住就好,接下来就是判断数组中的数字是否有重复,这一个地方由于允许使用另外的数组,所以其实还是比较简单的,另第二个数组存放最终的输出结果,对原数组进行遍历,每次检查原数组对应元素是否出现在第二个数组即可,当然有兴趣的同学可以研究一下哈希算法,这种算法可以很简单地实现去重的目的,C++中常见的对应数据结构为哈希表
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int nums[100]={0};
int count=0;
int x=0;
while(cin >>x)
{
nums[count++]=x;
}
int ans[count]={0};
int ansIndex=0;
bool notFound=true;
for(int i=0;i<count;i++)
{
notFound = true;
for(int j=0;j<ansIndex;j++)
{
if(ans[j]==nums[i])
{
notFound=false;
break;
}
}
if(notFound)
{
ans[ansIndex++]=nums[i];
}
}
for(int i=0;i<ansIndex;i++)
{
cout <<ans[i]<<" ";
}
return 0;
}
第三题
这个题目如果限制不允许使用第二个数组难度就大起来了,因为题目要求的是按照原来的顺序输出,这就限制了我们使用sort随后去重的手段,那么思路就得发生一些转变
- 首先是要求数组元素按照首次出现顺序输出,所以自然想得到我们要将后面的重复数字删除,所以不妨从后往前遍历,对每个数字,如果数组在它之前有它的重复元素,那么就将它剔除(此处用到的方法是置0,因为题目给出了元素的范围),这样就可以轻松得到一个含有多余的0的数组
- 接下来,题目要求输出的时候不能额外判断,那该怎么办呢,就需要将所有的0后置。这个就涉及到之前提及的双指针的思想,我们可以用一个指针cur遍历数组,同时用另一个指针pre指向当前的非零数组的下一位,每次cur遍历到0,则将cur往后移动到cur指向的元素非0或者遍历完成,将非零的数据移动到pre指向的位置,重复这个思路就可以将所有非0元素移动到0之前
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int a[100];
int n=0;
while (cin>>a[n])
{
n++;
}
for (int i=n-1;i>=0;i--)
{
for (int j=i-1;j>=0;j--)
{
if (a[j]==a[i]) {
a[i]=0;
break;
}
}
}
//所有的数字移动到0的前面
int pre=0;
int current=0;
while(current<n)
{
if(a[current]==0)
{
while(current<n&&a[current]==0)
current++;
if(current<n)
{
a[pre++]=a[current++];
}
}
else
{
a[pre++]=a[current++];
}
}
for (int i=0;i<pre;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
第四题
进制转换是非常经典的题目了,之前也应该提到过,转化为n进制,就是不断重复取余和相除这两个操作值得一提的是,当前字符应该是插入已生成字符的前面,否则最后结果需要逆序一下,转化的这个部分就不赘述了。主要讲下回文的判断,这个还是老办法,一个双指针就可以解决,设立头尾两个指针,每次判断完之后指针向中间移动知道相遇,这样就可以判断这个字符串是否关于中心对称,也就是是否是回文子字符串
#include <iostream>
#include <algorithm>
#include <sstream>
#include <string>
using namespace std;
int main()
{
int B;
cin>>B;
for (int i=1;i<=200;i++)
{
int m=i*i;
int m1=i;
string str1;
while (m1!=0)
{
if (m1%B < 10)
{
str1=to_string(m1%B)+str1;
}
else
{
str1=string(1,'A'+(m1%B)-10)+str1;
}
m1/=B;
}
string str;
while (m!=0)
{
if (m%B < 10)
{
str=to_string(m%B)+str;
}
else
{
str=string(1,'A'+(m%B)-10)+str;
}
m/=B;
}
bool flag=true;
for (int j=0;j<str.length()/2;j++)
{
if (str[j]!=str[str.length()-1-j])
{
flag=false;
break;
}
}
if (flag) cout<<str1<<" "<<str<<endl;
}
return 0;
}