华为机试训练做题总结(一)
2017-11-04 21:20
246 查看
1.字符串最后一个单词的长度
题目描述:计算字符串最后一个单词的长度,单词以空格隔开。
思路分析:看到这一题,开始我也没啥想法,想要去看答案,然后忍住了,稍微想了想,这一题其实挺简单的。不就是最后单词的长度,直接跑到字符串的最后,然后朝前数字符串到空格就行了。但是后来看别人的正确答案,发现自己考虑问题还是不够全面,这一题还需要考虑字符串最后是好几个空格的情况。因此需要设置一个flag当跑到最后一个单词的屁股的时候,将其置零。还有一个问题就是输入的问题,虽然没有仔细考虑到这个小细节,但是整体的思路还是正确的,但是最后正确率总停留在30%,一直没想明白,后来明白了。看完OJ的规则,发现不定量的输入需要使用getline(cin,str),读取字符串,这样可以完全读取字符串。我开始使用的是定义string str,这样会有一个问题就是输入的时候会导致输入断流。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
int count=0;
int len=str.length();
int flag=1;
for(int i=len-1;i>=0;--i){
if(flag && str[i]==' ')
continue;
else if(str[i]!=' ' ){
flag=0;
++count;
}else
{
break;
}
}
cout<<count<<endl;
}
return 0;
}
2.计算字符个数
题目描述:写出一个程序,接受一个有字母和数字以及空格组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数。不区分大小写。
思路分析:这个代码只有30%的通过率,百思不得其解。我的主要思想就是通过逆序将最后一个字符提取,然后再重新顺序遍历空格之前的字符串,与提取的字符相同的就计数。讲道理,应该不会有问题,求大神解答!
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
char com;
int endnum=0;
while(getline(cin,str))
{
int len=str.length();
int flag=1;
for(int i=len-1;i>=0;i--)
{
if(flag && str[i]==' ')
{
continue;
}else if(str[i]!=' '){
flag=0;
com=str[i];
endnum=i;
break;
}else
break;
}
}
int count=0;
for(int i=0;i<(endnum-1);i++){
char res=str[i];
if(res==com || res==(com-32))
count++;
}
cout<<count<<endl;
return 0;
}
3.明明的随机数
题目描述:明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
思路分析:开始把题目想错了,其实这个题目是提供随机数的 不需要自己生成,所以是多case问题,因此需要采用while(cin>>n)进行输入,然后将还有一个就是set 这个数据库的掌握,set通过insert进行输入,并且set这个数据结构只允许出现一次,并且在其中进行排好序了,复杂度在log2.非常高效的数据结构。对set数据结构进行遍历采用指针
set<int>::const_iterator p。
还有一个非常巧妙的桶排序,就是输入的每个数作为下标,然后进行计数,然后再遍历就是了。注意的是,数组需要在while循环内进行初始化。
代码:
#include<iostream>
#include<set>
using namespace std;
int main(){
int n;
set<int>res;
int temp;
while(cin>>n){
for(int i=0;i<n;i++){
cin>>temp;
res.insert(temp);
}
for(set<int>::const_iterator p= res.begin();p!=res.end();p++)
{
cout<<*p<<endl;
}
res.clear();
}
return 0;
}
4.字符串分隔
题目描述:•连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
思路分析:这一题还是比较简单,主要思路就是整除和求余,如果遇到八的倍数就记录下来,然后按照八的倍数进行输出,然后余数判断,只要是存在余数就输出然后再后面补上‘0’就行,然后不用考虑输入几次的问题,只要一劲儿输入就行,因为用的while(cin>>n)
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(cin>>str){
int len=str.length();
int yu=len%8;
int beishu=len/8;
for(int i=0;i<beishu;i++)
{
for(int j=0+8*i;j<8+8*i;j++)
{
cout<<str[j];
}
cout<<endl;
}
for(int i=beishu*8;i<beishu*8+yu;i++)
{
cout<<str[i];
}
if(yu!=0){
for(int i=beishu*8+yu;i<8+beishu*8;i++)
{
cout<<'0';
}
cout<<endl;
}
}
return 0;
}
5.进制转换
题目描述:写出一个程序,接受一个十六进制的数值字符串,输出该数值的十进制字符串。(多组同时输入 )
思路分析:因为题目提示的是多组进行输入因此需要采用while(cin>>string),不然会出现错误,然后还有一个就是最终输出的定义一定要放在while的循环内部,不然输出也会出现错误。
代码:
#include<iostream>
#include<math.h>
#include<string>
using namespace std;
int main(){
//进制转换一般就是 先除以该进制,然后转换为二进制 然后二进制转换为十进制
string str;
while(cin>>str){
int res=0;
for(int i=2;i<str.size();i++){
if(str[i]<='F' && str[i]>='A')
{
res=(str[i]-'A'+10)*pow(16,(str.size()-i-1))+res;
}
if(str[i]<='9' && str[i]>='0')
{
res=(str[i]-'0')*pow(16,(str.size()-i-1))+res;
}
}
cout<<res<<endl;
}
return 0;
}
6.质数因子
题目描述:
功能:输入一个正整数,按照从小到大的顺序输出它的所有质数的因子(如180的质数因子为2 2 3 3 5 )
最后一个数后面也要有空格
思路分析:这一题刚拿到手,我表示我是闷逼的,我一想直接就是质数,那怎么求出所有的质数呢。这是直接就固定思维 了。其实换个角度想想,求质数分解其实就是从最小的2,3开始分解的,如果这些比较小的数,都被分解完才能轮到比较大的数,因此直接就是循环,2分解一次,再分解一次,不能被2分解了再加,最终就能求出所有的质数。
代码:
#include<iostream>
using namespace std;
int main(){
long input_data;
while(cin>>input_data){
while(input_data!=1){
for(int i=2;i<=input_data;i++)
{
if(input_data%i==0)
{
input_data=input_data/i;
cout<<i<<" ";
break;
}
}
}
}
return 0;
}
7.取近似值
题目描述:
功能:
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。
思路分析:这一题,我也不知道怎么说就是一个int double / %的应用
代码:
#include<iostream>
using namespace std;
int main(){
double res;
while(cin>>res){
int temp=(int)res;
res=res*10;
temp=res-temp*10;
if(temp>=5)
res=int(res)/10+1;
else
res=int(res)/10;
cout<<res;
}
return 0;
}
8.合并表记录
题目描述:数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
思路分析:这一题有相同项的相加,由于之前遇到过一题类似的,一下子想到了水桶排序,思路很简单,做的过程,还需要注意细节,其他都还好,哈哈哈。
代码:
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<int>res(1000,0);
int temp1;
int temp2;
for(int i=0;i<n;i++){
cin>>temp1;
cin>>temp2;
res[temp1]=res[temp1]+temp2;
}
for(int i=0;i<1000;i++)
{
if(res[i]!=0)
{
cout<<i<<" "<<res[i]<<endl;
}
}
}
return 0;
}
9.提取不重复的整数
题目描述:输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
思路分析:这一题主要思路就是把重复的都剔除然后反过来读出,实际上就是在剔除上要花功夫,我采用的是遍历,如果和前面一致我就不存,并且设置一个哨兵,如果有和前面的一致的我就不增加计数。常规思路吧。
代码:
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<int>res(100,0);
int temp=0;
int counter=0;
int flag=0;
res[0]=n%10;
n=n/10;
while(n!=0){
temp=n%10;
counter++;
flag=0;
for(int i=0;i<counter;i++){
if(temp==res[i])
{
flag=1;
counter--;
break;
}
}
if(flag==0){
res[counter]=temp;
}
n=n/10;
}
int new_num=0;
for(int i=0;i<=counter;i++){
new_num=new_num+res[i]*pow(10,counter-i);
}
cout<<new_num;
}
return 0;
}
10.字符个数统计
题目描述:
编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127)。不在范围内的不作统计。
思路分析:这一题也是典型的水桶排序题,就是设置一个那么大的数组然后将对应的元素输入进去,但是这里,我搞错了一个东西,就是数组大于0,就是存在至少含有一个字符的个数。
代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
string str;
while(cin>>str){
int temp=0;
int count=0;
vector<int>res(128,0);
for(int i=0;i<str.length();i++){
temp=str[i]-' ';
if(temp<128 && temp>=0)
res[temp]++;
}
for(int i=0;i<127;i++){
if(res[i]>0)
count++;
}
cout<<count;
}
return 0;
}
11.数字颠倒
题目描述:
编
输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001
思路分析:这一题我真不知道该怎么说了,实在是太搞笑了,我想多了实际就是直接输出一个加上‘0’的字符就行,主体考察的就是一个整除和求余的操作。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
int num;
while(cin>>num){
char temp;
while(num){
temp=num%10+'0';
cout<<temp;
num/=10;
}
}
return 0;
}
12.字符串反转
题目描述:
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。例如:
思路分析:这一题我真不知道该怎么说了,实在是太搞笑了,其实这一题就是你明白了OJ系统之后钻的一个空子。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(cin>>str){
for(int i=str.length()-1;i>=0;i--)
{
cout<<str[i];
}
}
return 0;
}
13.句子逆序
题目描述:
将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”
所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符
接口说明
/**
* 反转句子
*
* @param sentence 原句子
* @return 反转后的句子
*/
public String reverse(String sentence);
思路分析:这一题主体思想没啥大的问题,但是在输入的时候和细节把握发现很多问题。比如输入的问题是cin>>怎么都没法使程序通过,然而之前使用cin毫无问题,之后换了getline(cin,str)问题就解决了,我不知道具体的原因,我猜想是这个问题的特殊,造成的。因为输入的是句子,最终是要有回车的。因此采用cin无法使回车产生作用。还有一个细节的问题就是最后一个字符串的出现,没有考虑好,应该对最后一个字符进行单独考虑。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
for(int i=str.length()-1;i>0;i--){
if(str[i]==' '){
for(int j=i+1;str[j]!=' ' && j<(str.length());j++)
{
cout<<str[j];
}
cout<<' ';
}
}
for(int i=0;str[i]!=' ';i++){
cout<<str[i];
}
}
return 0;
}
14.字符串连接最长路径的查找
题目描述:
给定n个字符串,请对n个字符串按照字典序排列。
思路分析:这一题其实也很简单,关键点就两个遍历和比较,遍历我用的最笨的方法,双重循环,比较我比较犯傻,没有掌握string的特殊特性,string类型自带比较属性,我还吭哧地写了个函数,结果那个函数还是错的,跪 了。需要注意的是vector<string>str(n)需要给出n的大小,然后比较,最后还要有clear函数,不然可能会溢出。还有双重循环的时候注意起始。
代码:
#include<iostream>
#include<string>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<string>str(n);
for(int i=0;i<n;i++){
cin>>str[i];
}
string temp;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++){
if(str[i]>str[j])
{
temp=str[i];
str[i]=str[j];
str[j]=temp;
}
}
}
for(int i=0;i<n;i++){
cout<<str[i]<<endl;
}
str.clear();
}
return 0;
}
15.求int型正整数在内存中存储时1的个数
题目描述:
输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数。
思路分析:这一题感觉还是基础不够扎实啊,别人都用很精妙的方法求的,感觉自己的差距还是有的。回到正题一个,就是利用对数字求2的余,判断是否有1,对2求商逐位判断。还有一个就是利用
代码:
#include<iostream>
using namespace std;
int main(){
int num;
while(cin>>num){
int count=0;
while(num){
if(num%2)
count++;
num/=2;
}
cout<<count;
}
return 0;
}
16.购物车
题目描述:
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。
思路分析:实在是吐了,啥不想看了,想死,就是一个动态规划问题,需要存储值,然后采用动态规划把结果计算出来, 判断不同的情况,可以采用多种判断的语句。
但是也学到了一些看似没用的东西:
万能的头文件:#include<bits/stdc++.h>
cnt表示计数
1<<j 1向左位移j个单位
代码:
#include <iostream>
#include <algorithm>
#define max(x,y) (x)>(y)?(x):(y)
using namespace std;
int main()
{
int N,m; //N 总钱数 m为购买物品个数
int weight[61][3]={0};
int value[61][3] = {0};
while(cin>>N>>m)
{
int dp[61][3201] = {0};
N /= 10; //都是10的整数倍 节约空间
int v,p,q;
for(int i=1;i<=m;i++)
{
cin>>v>>p>>q;
p = p*v;
v /= 10;
//按主件附件分类 第二个小标表示是第i件物品还是主件附件
if(q==0)
{
weight[i][q] = v;
value[i][q] = p;
}
else if(weight[q][1]==0)
{
weight[q][1] = v;
value[q][1] = p;
}
else
{
weight[q][2] = v;
value[q][2] = p;
}
}
//开始进行动态规划
for(int i=1;i<=m;i++)
for(int j=1;j<=N;j++)
{
dp[i][j] = dp[i-1][j];
if(weight[i][0]<=j)
{
int t = max(dp[i-1][j],dp[i-1][j-weight[i][0]]+value[i][0]);
if(t>dp[i][j])
dp[i][j] = t;
}
if(weight[i][0]+weight[i][1]<=j)
{
int t = dp[i-1][j-weight[i][0]-weight[i][1]]+value[i][0]+value[i][1];
if(t>dp[i][j])
dp[i][j] = t;
}
if(weight[i][0]+weight[i][2]<=j)
{
int t = dp[i-1][j-weight[i][0]-weight[i][2]]+value[i][0]+value[i][2];
if(t>dp[i][j])
dp[i][j] = t;
}
if(weight[i][0]+weight[i][1]+weight[i][2]<=j)
{
int t = dp[i-1][j-weight[i][0]-weight[i][1]-weight[i][2]]+value[i][0]+value[i][1]+value[i][2];
if(t>dp[i][j])
dp[i][j] = t;
}
}
cout<<dp[m]
<<endl;
}
return 0;
}
17.坐标移动
题目描述:
开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。
思路分析:这一题思路主要就是就是字符串和数字之间的关系,还有一个就是寻找;之间的字符个数,这一题停留了挺长时间的,主要的问题出在了一个循环上面,其中的判断条件没有用对,再加上不太会debug找到问题的所在,所以一直愣在这儿,没有继续朝下做。
感悟:一个就是要把其中要输出的部分写在while循环里面,还有一个就是debug 的技巧就是将不同的部分注释掉,然后只留下想debug的部分。
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
//设置初始坐标 和 移动数值
int x=0;
int y=0;
int dx=0;
int dy=0;
int tempj=0;
int tempi=0;
for(int i=0;i<str.length();i++){
tempi=i;
if(str[i]==';' )
{
int count=0;
for(int j=tempi-1;j>=0 && str[j]!=';';j--)
{
if(str[j]<='Z' && str[j]>='A' && str[j]!='A' && str[j]!='D' && str[j]!='W' && str[j]!='S')
{
count=2;
}
if(str[j]=='A' || str[j]=='D' || str[j]=='W' || str[j]=='S'){
count++;
}
tempj=j;
}
if(count>=2)
break;
if(str[tempj]=='A')
{
for(int k=tempj+1;k<tempi;k++)
{
dx+=-(str[k]-'0')*pow(10,tempi-k-1);
}
}
if(str[tempj]=='D')
{
for(int k=tempj+1;k<tempi;k++)
{
dx+=(str[k]-'0')*pow(10,tempi-k-1);
}
}
if(str[tempj]=='W')
{
for(int k=tempj+1;k<tempi;k++)
{
dy+=(str[k]-'0')*pow(10,tempi-k-1);
}
}
if(str[tempj]=='S')
{
for(int k=tempj+1;k<tempi;k++)
{
dy+=-(str[k]-'0')*pow(10,tempi-k-1);
}
}
}else
continue;
}
x=dx;
y=dy;
cout<<x<<","<<y<<endl;
}
return 0;
}
18.识别有效IP地址和掩码并进行分类统计
题目描述:
请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。
思路分析:到最后这一题我也没看懂,主要不知道 这一题的标准是是是什么,然后通过看别
人通过的代码,大体懂了一些,然后主要学习到了string和int 两个类型之间转换的方式
主要通过 atoi(str.c_str())函数实现string到int 类型的转换(其中c_str()是将string 转
为 char* 类型)。然后是string这个数据结构中substr函数的应用,str.substr(子串开始
的位置,子串的长度),还有一个就是string数据结构find函数的应用,str.find(' ~') 发
现字符在原字符串中的位置。
还有一个有疑问的地方就是自己写了一个函数什么时候使用引用,什么时候不用使用引
用,这个地方比较疑惑。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void split(string& str, vector<string>& strs){
int pos=str.find('.');
while(pos>=0){
strs.push_back(str.substr(0, pos));
str=str.substr(pos+1, str.length()-pos-1);
pos=str.find('.');
}
strs.push_back(str);
}
bool checkNum(string& str){
if(str.size()==0 || str.size()>3)
return false;
for(int i=0; i<str.size(); i++){
if(str[i]<'0' || str[i]>'9')
return false;
}
int num=atoi(str.c_str());
if(num>=0 && num<=255)
return true;
return false;
}
bool checkIP(vector<string>& segs){
if(segs.size()!=4)
return false;
for(int i=segs.size()-1; i>=0; i--){
if(!checkNum(segs[i]))
return false;
}
//if(atoi(segs[0])==127)
// return false;
return true;
}
bool checkMask(vector<string>& segs){
if(segs.size()!=4)
return false;
bool start=false;
for(int i=0; i<segs.size(); i++){
if(!checkNum(segs[i]))
return false;
int num=atoi(segs[i].c_str());
if(start){
if(num!=0)
return false;
}else{
if(num!=255){
if(num==0 || num==128 || num==192 || num==224 || num==240 || num==248 || num==252 || num==254)
start=true;
else
return false;
}
}
}
if(atoi(segs[3].c_str())==255)
return false;
return true;
}
void classify(vector<string>& ip, vector<int>& counter){
int n1=atoi(ip[0].c_str());
int n2=atoi(ip[1].c_str());
if(n1>=1 && n1<=126){
if(n1==10)
counter[6]++;
counter[0]++;
}else if(n1>=128 && n1<=191){
if(n1==172 && n2>=16 && n2<=31)
counter[6]++;
counter[1]++;
}else if(n1>=192 && n1<=223){
if(n1==192 && n2==168)
counter[6]++;
counter[2]++;
}else if(n1>=224 && n1<=239)
counter[3]++;
else if(n1>=240 && n1<=255)
counter[4]++;
}
int main(){
vector<int> counter(7, 0);
int W=0, P=0;
string str;
while(cin>>str){
int pos=str.find('~');
string ip=str.substr(0, pos);
string mask=str.substr(pos+1, str.length()-pos-1);
vector<string> ip_segs, mask_segs;
split(ip, ip_segs);
split(mask, mask_segs);
if(!checkIP(ip_segs) || !checkMask(mask_segs))
counter[5]++;
else
classify(ip_segs, counter);
}
cout<<counter[0]<<" "<<counter[1]<<" "<<counter[2]<<" "<<counter[3]<<" "<<counter[4]<<" "<<counter[5]<<" "<<counter[6]<<endl;
return 0;
}
19.简单错误记录
题目描述:
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
思路分析:
这一题很奇怪,明明我输出的内容和对应的输出是一样的,但是还是没有通过,但是代码还是要贴出来的。通过这一题,学到了很多关于string类型吧函数的使用方法,以及一些特殊的关键字。
比如: string 的rfind函数:
就是发现字符串中指定字符所在最后一个位置的函数,通过这个函数你可以方便的找到
最后一次出现该字符的位置。
string类型的substr函数:
substr(pos),就是表示直接从pos位置向后的子字符串,还有一种表示方式是
substr(pos,length),表示从pos位置向后length距离的子字符串。
结构体的使用:
结构体最早接触是在c语言中,当时学习学的也是稀里糊涂,纯粹为了考试,并没有真
正想着如何取用。这一题中结构通过将两个判别数据以及一个存储数据放进来。并且实
现了运算符重载(这让我非常惊讶,结构体竟然能够运算符重载!!!) 还有一个让我
非常惊讶的就是结构体,竟然能和数据类型一样存在vecotr里面!!!直接就是一种数
据类型。其中结构体的变量赋值直接就是在结构体里面构造初始化函数和类的写法一
样。
vector查询相同变量内容:
可能这里我的话没说清楚,意思就是查询一个vector类型存储的内容里面有没有我们想
要的内容。这个查找方法是 auto res=find(myvec.begin(),myvec.end(),temp);
如果res==myvec.begin()就说明这个里面不存在,我们想找的temp。
其中res的类型,也可以是vector<erroNode>::iterator 就是一个指针类型,查找元素用
的。
贴代码:
#include<bits/stdc++.h>
using namespace std;
string getFileName(string path){
int pos=path.rfind('\\');
return path.substr(pos+1);
}
string modifyName(string name){
if(name.size()>16){
name=name.substr(name.size()-16);
}
return name;
}
struct ErrRecord{
string file;
int lineNo;
int count;
ErrRecord(string file,int lineNo){
this->file=file;
this->lineNo=lineNo;
count=1;
}
bool operator ==(const ErrRecord &a){
return (file== a.file) && (lineNo == a.lineNo);
}
};
int main(){
string file;
int lineNo;
vector<ErrRecord>myvec;
while(cin>>file>>lineNo){
ErrRecord record(getFileName(file),lineNo);
auto res=find(myvec.begin(),myvec.end(),record);
if(res==myvec.end()){
myvec.push_back(record);
}else{
res->count++;
}
}
int count=0;
for(auto item:myvec){
if(count+8 >=myvec.size()){
cout<<modifyName(item.file)<<" "<<item.lineNo<<" "<<item.count<<endl;
}
count++;
}
return 0;
}
20.密码验证合格程序
题目描述:
密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有相同长度超2的子串重复
说明:长度超过2的子串
思路分析:
这一题思路还是比较简单的,就是将三个条件进行判断就行了,开始还在为自己一遍通过,感觉沾沾自喜,后来看到了大神的AC,感觉自己还是个老实人,没有将效率进一步提高。其实判断子字符串完全可以只判断三个长度的子字符串,因为大于三个长度的子字符串完全是不用对比的。
老实人的代码:
#include<bits/stdc++.h>
using namespace std;
//写一个函数判断符号的种类
bool modifyNote(string str){
vector<int>count(4,0);
int zero_num=0;
for(int i=0;i<str.length();i++){
if(str[i]>='A' && str[i]<='Z')
{
count[0]++;
}else if(str[i]>='a' && str[i]<='z')
{
count[1]++;
}else if(str[i]>='0' && str[i]<='9')
{
count[2]++;
}else
{
count[3]++;
}
}
for(int i=0;i<4;i++)
{
if(count[i]==0)
zero_num++;
}
if(zero_num<=1)
return false;
else
return true;
}
//写一个函数用来判断长度超过2的子串 是否有重复的子字符串
//返回true 说明有相同的子字符串 返回false 则说明没有相同的子字符串。
bool substr_judge(const string str ){
string sub_str;
for(int i=0;i<str.length();i++){
for(int j=3;j<str.length();j++){
sub_str=str.substr(i,j);
//开始进行对比
for(int k=i+1;k<(str.length()-j);k++){
if(sub_str==str.substr(k,j))
return true;
}
}
}
return false;
}
int main(){
string str;
while(cin>>str){
if(str.length()<=8)
{
cout<<"NG"<<endl;
}else if(substr_judge(str)){
cout<<"NG"<<endl;
}else if(modifyNote(str))
cout<<"NG"<<endl;
else
cout<<"OK"<<endl;
}
return 0;
}
21.简单密码
题目描述:
假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。
思路分析:
这一题不难,但是还是停留了好长时间,这主要是因为,遇到一个很坑的一个东西,就是你在if语句判断的时候,
能用if-elseif就尽量用,别用if-if 不然华为OJ很容易出错!!!
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
//变换主要针对于大小写字母 其他都不变
string str;
while(cin>>str){
int num=('a'-'A')+1;
for(int i=0;i<str.length();i++){
if(str[i]=='Z')
str[i]='a';
else if(str[i]>='A' && str[i]<'Z'){
str[i]=(char)(str[i]+num);
}else if(str[i]>='a' && str[i]<='z'){
switch(str[i]){
case 'a':
case 'b':
case 'c':
{ str[i]='2';
break;
}
case 'd':
case 'e':
case 'f':
{
str[i]='3';
break;
}
case 'g':
case 'h':
case 'i':
{
str[i]='4';
break;
}
case 'j':
case 'k':
case 'l':
{
str[i]='5';
break;
}
case 'm':
case 'n':
case 'o':
{
str[i]='6';
break;
}
case 'p':
case 'q':
case 'r':
case 's':
{
str[i]='7';
break;
}
case 't':
case 'u':
case 'v':
{
str[i]='8';
break;
}
case 'w':
case'x':
case 'y':
case 'z':
{
str[i]='9';
break;
}
}
}
}
cout<<str<<endl;
}
return 0;
}
22.汽水瓶
题目描述:
有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?
思路分析:
这一题一遍过,掌握了规律真的很简单。然后这个规律是我猜的。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int num;
while(cin>>num){
if(num==0)
break;
num=num/2;
cout<<num<<endl;
}
return 0;
}
23.删除字符串中出现次数最少字符
题目描述:
实现删除字符串中出现次数最少的字符,若多个字符出现次数一样,则都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。
思路分析:
这一题逻辑难度不大,常规的一套思路走下来,基本就能完成,但是实现的时候,感觉难度还是有的,花了挺长时间的,感觉功力还是需要加强的
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
while(cin>>str){
int temp=20;
vector<int>pos;
vector<int>counter(26,0);
for(int i=0;i<str.length();i++){
counter[str[i]-'a']++;
}
for(int i=0;i<26;i++){
if(counter[i]<=temp && counter[i]!=0){
temp=counter[i];
}
}
for(int i=0;i<str.length();i++){
if(temp==counter[str[i]-'a'])
continue;
else
cout<<str[i];
}
cout<<endl;
}
return 0;
}
24.数据分类处理
题目描述:
信息社会,有海量的数据需要分析处理,比如公安局分析身份证号码、 QQ 用户、手机号码、银行帐号等信息及活动记录。
采集输入大数据和分类规则,通过大数据分类处理程序,将大数据分类输出。
思路分析:
这一题也想了一种解决的思路出来,但是后来解决的方法越来越负责,直接就放弃了。 后来找了一种还算比较简单的,思路还比较类似的。然后讲讲主要是怎么实现的吧。主要就是利用
vector先存储主要的元素,然后利用set这种数据结构排序去重的属性,先存储R类,然后再将其元素存储到vector数据结构中,然后利用stringstream将int转为string类型,然后利用find函数,发现子字符串的话find返回值就是 string::npos,然后如果符合条件的就放进结果的向量里面并且技术
感悟:
int->string
采用stringstream temp, string str; temp<<int_num; temp>>str;
set数据结构
采用set数据结构可以直接进行排序去重,同时插入形式是insert();
vector类型
vector进行排序的函数sort(vec.begin(),vec.end());vector 进行整段插入采用
采用的是insert()函数,insert(result.end(),temp.begin(),temp.end());其中
insert(result.begin(),val),表示在最前面插入元素值
insert(result.end(),val),表示在最后插入元素。
string类型
string 类查找字符串中是否有子串可以通过find函数,str.find(substr),如果返回值是std::string::npos 则说明字符串中存在需要查找的子串。
同时回顾一下之前的rfind函数,就是发现字符串中指定字符所在最后一个位置的函数,通过这个函数你可以方便的找到最后一次出现该字符的位置。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<int>I(n);
for(int i=0;i<n;i++){
cin>>I[i];
}
int m;
cin>>m;
set<int>temp;
for(int i=0;i<m;i++){
int a;
cin>>a;
temp.insert(a);
}
vector<int>R;
set<int>::iterator iter=temp.begin();
while(iter!=temp.end()){
R.push_back(*iter);
++iter;
}
sort(R.begin(),R.end());
vector<int>result;
for(int i=0;i<R.size();i++){
stringstream ss1;
string str1;
ss1<<R[i];
ss1>>str1;
int ret=0;
vector<int>temp_result;
for(int j=0;j<n;j++){
stringstream ss;
string str;
ss<<I[j];
ss>>str;
size_t found=str.find(str1);
if(found!=std::string::npos){
temp_result.push_back(j);
temp_result.push_back(I[j]);
ret++;
}
}
if(ret){
result.push_back(R[i]);
result.push_back(ret);
result.insert(result.end(),temp_result.begin(),temp_result.end());
}
}
result.insert(result.begin(),result.size());
for(int i=0;i<result.size()-1;i++){
cout<<result[i]<<" "<<endl;
}
cout<<result[result.size()-1]<<endl;
}
return 0;
}
25.字符串排序
题目描述:
写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
样例:
输入:
A Famous Saying: Much Ado About Nothing(2012/8).
输出:
A aaAAbc dFgghh : iimM nNn oooos Sttuuuy (2012/8).
思路分析:
其实这一题总有一种一眼看穿的感觉,总有种一下子就能做出来的感觉,但是 看了好久还是没有进展,后来看看别人的做法,发现其实初始的想法还是已经和解决方案还是很近了。但是没有坚持下去。可惜。
但是需要注意的地方还是有很多的。
比如vector<char>temp 变量的设置,需要将vector里面的类型设置为char不然无法进行push_back。
另外一个需要注意的地方就是核心,需要将从1-26个字母依次存储就是依次减去'a' 'A'之后对应的数字。
还有一个就是将排好顺序的字符串赋值给原来的字符串的地方需要注意。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
vector<char>temp;
while(cin>>str){
temp.clear();
for(int i=0;i<26;i++){
for(int j=0;j<str.size();j++){
if(str[j]-'a'==i || str[j]-'A'==i){
temp.push_back(str[j]);
}
}
}
for(int i=0 ,j=0;i<str.size() && j<temp.size();i++){
if(str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z'){
str[i]=temp[j++];
}
}
cout<<str<<endl;
}
return 0;
}
题目描述:计算字符串最后一个单词的长度,单词以空格隔开。
思路分析:看到这一题,开始我也没啥想法,想要去看答案,然后忍住了,稍微想了想,这一题其实挺简单的。不就是最后单词的长度,直接跑到字符串的最后,然后朝前数字符串到空格就行了。但是后来看别人的正确答案,发现自己考虑问题还是不够全面,这一题还需要考虑字符串最后是好几个空格的情况。因此需要设置一个flag当跑到最后一个单词的屁股的时候,将其置零。还有一个问题就是输入的问题,虽然没有仔细考虑到这个小细节,但是整体的思路还是正确的,但是最后正确率总停留在30%,一直没想明白,后来明白了。看完OJ的规则,发现不定量的输入需要使用getline(cin,str),读取字符串,这样可以完全读取字符串。我开始使用的是定义string str,这样会有一个问题就是输入的时候会导致输入断流。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
int count=0;
int len=str.length();
int flag=1;
for(int i=len-1;i>=0;--i){
if(flag && str[i]==' ')
continue;
else if(str[i]!=' ' ){
flag=0;
++count;
}else
{
break;
}
}
cout<<count<<endl;
}
return 0;
}
2.计算字符个数
题目描述:写出一个程序,接受一个有字母和数字以及空格组成的字符串,和一个字符,然后输出输入字符串中含有该字符的个数。不区分大小写。
思路分析:这个代码只有30%的通过率,百思不得其解。我的主要思想就是通过逆序将最后一个字符提取,然后再重新顺序遍历空格之前的字符串,与提取的字符相同的就计数。讲道理,应该不会有问题,求大神解答!
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
char com;
int endnum=0;
while(getline(cin,str))
{
int len=str.length();
int flag=1;
for(int i=len-1;i>=0;i--)
{
if(flag && str[i]==' ')
{
continue;
}else if(str[i]!=' '){
flag=0;
com=str[i];
endnum=i;
break;
}else
break;
}
}
int count=0;
for(int i=0;i<(endnum-1);i++){
char res=str[i];
if(res==com || res==(com-32))
count++;
}
cout<<count<<endl;
return 0;
}
3.明明的随机数
题目描述:明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。
思路分析:开始把题目想错了,其实这个题目是提供随机数的 不需要自己生成,所以是多case问题,因此需要采用while(cin>>n)进行输入,然后将还有一个就是set 这个数据库的掌握,set通过insert进行输入,并且set这个数据结构只允许出现一次,并且在其中进行排好序了,复杂度在log2.非常高效的数据结构。对set数据结构进行遍历采用指针
set<int>::const_iterator p。
还有一个非常巧妙的桶排序,就是输入的每个数作为下标,然后进行计数,然后再遍历就是了。注意的是,数组需要在while循环内进行初始化。
代码:
#include<iostream>
#include<set>
using namespace std;
int main(){
int n;
set<int>res;
int temp;
while(cin>>n){
for(int i=0;i<n;i++){
cin>>temp;
res.insert(temp);
}
for(set<int>::const_iterator p= res.begin();p!=res.end();p++)
{
cout<<*p<<endl;
}
res.clear();
}
return 0;
}
4.字符串分隔
题目描述:•连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
思路分析:这一题还是比较简单,主要思路就是整除和求余,如果遇到八的倍数就记录下来,然后按照八的倍数进行输出,然后余数判断,只要是存在余数就输出然后再后面补上‘0’就行,然后不用考虑输入几次的问题,只要一劲儿输入就行,因为用的while(cin>>n)
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(cin>>str){
int len=str.length();
int yu=len%8;
int beishu=len/8;
for(int i=0;i<beishu;i++)
{
for(int j=0+8*i;j<8+8*i;j++)
{
cout<<str[j];
}
cout<<endl;
}
for(int i=beishu*8;i<beishu*8+yu;i++)
{
cout<<str[i];
}
if(yu!=0){
for(int i=beishu*8+yu;i<8+beishu*8;i++)
{
cout<<'0';
}
cout<<endl;
}
}
return 0;
}
5.进制转换
题目描述:写出一个程序,接受一个十六进制的数值字符串,输出该数值的十进制字符串。(多组同时输入 )
思路分析:因为题目提示的是多组进行输入因此需要采用while(cin>>string),不然会出现错误,然后还有一个就是最终输出的定义一定要放在while的循环内部,不然输出也会出现错误。
代码:
#include<iostream>
#include<math.h>
#include<string>
using namespace std;
int main(){
//进制转换一般就是 先除以该进制,然后转换为二进制 然后二进制转换为十进制
string str;
while(cin>>str){
int res=0;
for(int i=2;i<str.size();i++){
if(str[i]<='F' && str[i]>='A')
{
res=(str[i]-'A'+10)*pow(16,(str.size()-i-1))+res;
}
if(str[i]<='9' && str[i]>='0')
{
res=(str[i]-'0')*pow(16,(str.size()-i-1))+res;
}
}
cout<<res<<endl;
}
return 0;
}
6.质数因子
题目描述:
功能:输入一个正整数,按照从小到大的顺序输出它的所有质数的因子(如180的质数因子为2 2 3 3 5 )
最后一个数后面也要有空格
思路分析:这一题刚拿到手,我表示我是闷逼的,我一想直接就是质数,那怎么求出所有的质数呢。这是直接就固定思维 了。其实换个角度想想,求质数分解其实就是从最小的2,3开始分解的,如果这些比较小的数,都被分解完才能轮到比较大的数,因此直接就是循环,2分解一次,再分解一次,不能被2分解了再加,最终就能求出所有的质数。
代码:
#include<iostream>
using namespace std;
int main(){
long input_data;
while(cin>>input_data){
while(input_data!=1){
for(int i=2;i<=input_data;i++)
{
if(input_data%i==0)
{
input_data=input_data/i;
cout<<i<<" ";
break;
}
}
}
}
return 0;
}
7.取近似值
题目描述:
功能:
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。
思路分析:这一题,我也不知道怎么说就是一个int double / %的应用
代码:
#include<iostream>
using namespace std;
int main(){
double res;
while(cin>>res){
int temp=(int)res;
res=res*10;
temp=res-temp*10;
if(temp>=5)
res=int(res)/10+1;
else
res=int(res)/10;
cout<<res;
}
return 0;
}
8.合并表记录
题目描述:数据表记录包含表索引和数值,请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照key值升序进行输出。
思路分析:这一题有相同项的相加,由于之前遇到过一题类似的,一下子想到了水桶排序,思路很简单,做的过程,还需要注意细节,其他都还好,哈哈哈。
代码:
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<int>res(1000,0);
int temp1;
int temp2;
for(int i=0;i<n;i++){
cin>>temp1;
cin>>temp2;
res[temp1]=res[temp1]+temp2;
}
for(int i=0;i<1000;i++)
{
if(res[i]!=0)
{
cout<<i<<" "<<res[i]<<endl;
}
}
}
return 0;
}
9.提取不重复的整数
题目描述:输入一个int型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
思路分析:这一题主要思路就是把重复的都剔除然后反过来读出,实际上就是在剔除上要花功夫,我采用的是遍历,如果和前面一致我就不存,并且设置一个哨兵,如果有和前面的一致的我就不增加计数。常规思路吧。
代码:
#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<int>res(100,0);
int temp=0;
int counter=0;
int flag=0;
res[0]=n%10;
n=n/10;
while(n!=0){
temp=n%10;
counter++;
flag=0;
for(int i=0;i<counter;i++){
if(temp==res[i])
{
flag=1;
counter--;
break;
}
}
if(flag==0){
res[counter]=temp;
}
n=n/10;
}
int new_num=0;
for(int i=0;i<=counter;i++){
new_num=new_num+res[i]*pow(10,counter-i);
}
cout<<new_num;
}
return 0;
}
10.字符个数统计
题目描述:
编写一个函数,计算字符串中含有的不同字符的个数。字符在ACSII码范围内(0~127)。不在范围内的不作统计。
思路分析:这一题也是典型的水桶排序题,就是设置一个那么大的数组然后将对应的元素输入进去,但是这里,我搞错了一个东西,就是数组大于0,就是存在至少含有一个字符的个数。
代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main(){
string str;
while(cin>>str){
int temp=0;
int count=0;
vector<int>res(128,0);
for(int i=0;i<str.length();i++){
temp=str[i]-' ';
if(temp<128 && temp>=0)
res[temp]++;
}
for(int i=0;i<127;i++){
if(res[i]>0)
count++;
}
cout<<count;
}
return 0;
}
11.数字颠倒
题目描述:
编
输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001
思路分析:这一题我真不知道该怎么说了,实在是太搞笑了,我想多了实际就是直接输出一个加上‘0’的字符就行,主体考察的就是一个整除和求余的操作。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
int num;
while(cin>>num){
char temp;
while(num){
temp=num%10+'0';
cout<<temp;
num/=10;
}
}
return 0;
}
12.字符串反转
题目描述:
写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。例如:
思路分析:这一题我真不知道该怎么说了,实在是太搞笑了,其实这一题就是你明白了OJ系统之后钻的一个空子。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(cin>>str){
for(int i=str.length()-1;i>=0;i--)
{
cout<<str[i];
}
}
return 0;
}
13.句子逆序
题目描述:
将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”
所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符
接口说明
/**
* 反转句子
*
* @param sentence 原句子
* @return 反转后的句子
*/
public String reverse(String sentence);
思路分析:这一题主体思想没啥大的问题,但是在输入的时候和细节把握发现很多问题。比如输入的问题是cin>>怎么都没法使程序通过,然而之前使用cin毫无问题,之后换了getline(cin,str)问题就解决了,我不知道具体的原因,我猜想是这个问题的特殊,造成的。因为输入的是句子,最终是要有回车的。因此采用cin无法使回车产生作用。还有一个细节的问题就是最后一个字符串的出现,没有考虑好,应该对最后一个字符进行单独考虑。
代码:
#include<iostream>
#include<string>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
for(int i=str.length()-1;i>0;i--){
if(str[i]==' '){
for(int j=i+1;str[j]!=' ' && j<(str.length());j++)
{
cout<<str[j];
}
cout<<' ';
}
}
for(int i=0;str[i]!=' ';i++){
cout<<str[i];
}
}
return 0;
}
14.字符串连接最长路径的查找
题目描述:
给定n个字符串,请对n个字符串按照字典序排列。
思路分析:这一题其实也很简单,关键点就两个遍历和比较,遍历我用的最笨的方法,双重循环,比较我比较犯傻,没有掌握string的特殊特性,string类型自带比较属性,我还吭哧地写了个函数,结果那个函数还是错的,跪 了。需要注意的是vector<string>str(n)需要给出n的大小,然后比较,最后还要有clear函数,不然可能会溢出。还有双重循环的时候注意起始。
代码:
#include<iostream>
#include<string>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<string>str(n);
for(int i=0;i<n;i++){
cin>>str[i];
}
string temp;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++){
if(str[i]>str[j])
{
temp=str[i];
str[i]=str[j];
str[j]=temp;
}
}
}
for(int i=0;i<n;i++){
cout<<str[i]<<endl;
}
str.clear();
}
return 0;
}
15.求int型正整数在内存中存储时1的个数
题目描述:
输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数。
思路分析:这一题感觉还是基础不够扎实啊,别人都用很精妙的方法求的,感觉自己的差距还是有的。回到正题一个,就是利用对数字求2的余,判断是否有1,对2求商逐位判断。还有一个就是利用
a&=a-1;
//判断二进制有多少个
1
代码:
#include<iostream>
using namespace std;
int main(){
int num;
while(cin>>num){
int count=0;
while(num){
if(num%2)
count++;
num/=2;
}
cout<<count;
}
return 0;
}
16.购物车
题目描述:
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 | 附件 |
电脑 | 打印机,扫描仪 |
书柜 | 图书 |
书桌 | 台灯,文具 |
工作椅 | 无 |
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。
思路分析:实在是吐了,啥不想看了,想死,就是一个动态规划问题,需要存储值,然后采用动态规划把结果计算出来, 判断不同的情况,可以采用多种判断的语句。
但是也学到了一些看似没用的东西:
万能的头文件:#include<bits/stdc++.h>
cnt表示计数
1<<j 1向左位移j个单位
代码:
#include <iostream>
#include <algorithm>
#define max(x,y) (x)>(y)?(x):(y)
using namespace std;
int main()
{
int N,m; //N 总钱数 m为购买物品个数
int weight[61][3]={0};
int value[61][3] = {0};
while(cin>>N>>m)
{
int dp[61][3201] = {0};
N /= 10; //都是10的整数倍 节约空间
int v,p,q;
for(int i=1;i<=m;i++)
{
cin>>v>>p>>q;
p = p*v;
v /= 10;
//按主件附件分类 第二个小标表示是第i件物品还是主件附件
if(q==0)
{
weight[i][q] = v;
value[i][q] = p;
}
else if(weight[q][1]==0)
{
weight[q][1] = v;
value[q][1] = p;
}
else
{
weight[q][2] = v;
value[q][2] = p;
}
}
//开始进行动态规划
for(int i=1;i<=m;i++)
for(int j=1;j<=N;j++)
{
dp[i][j] = dp[i-1][j];
if(weight[i][0]<=j)
{
int t = max(dp[i-1][j],dp[i-1][j-weight[i][0]]+value[i][0]);
if(t>dp[i][j])
dp[i][j] = t;
}
if(weight[i][0]+weight[i][1]<=j)
{
int t = dp[i-1][j-weight[i][0]-weight[i][1]]+value[i][0]+value[i][1];
if(t>dp[i][j])
dp[i][j] = t;
}
if(weight[i][0]+weight[i][2]<=j)
{
int t = dp[i-1][j-weight[i][0]-weight[i][2]]+value[i][0]+value[i][2];
if(t>dp[i][j])
dp[i][j] = t;
}
if(weight[i][0]+weight[i][1]+weight[i][2]<=j)
{
int t = dp[i-1][j-weight[i][0]-weight[i][1]-weight[i][2]]+value[i][0]+value[i][1]+value[i][2];
if(t>dp[i][j])
dp[i][j] = t;
}
}
cout<<dp[m]
<<endl;
}
return 0;
}
17.坐标移动
题目描述:
开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。
思路分析:这一题思路主要就是就是字符串和数字之间的关系,还有一个就是寻找;之间的字符个数,这一题停留了挺长时间的,主要的问题出在了一个循环上面,其中的判断条件没有用对,再加上不太会debug找到问题的所在,所以一直愣在这儿,没有继续朝下做。
感悟:一个就是要把其中要输出的部分写在while循环里面,还有一个就是debug 的技巧就是将不同的部分注释掉,然后只留下想debug的部分。
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
//设置初始坐标 和 移动数值
int x=0;
int y=0;
int dx=0;
int dy=0;
int tempj=0;
int tempi=0;
for(int i=0;i<str.length();i++){
tempi=i;
if(str[i]==';' )
{
int count=0;
for(int j=tempi-1;j>=0 && str[j]!=';';j--)
{
if(str[j]<='Z' && str[j]>='A' && str[j]!='A' && str[j]!='D' && str[j]!='W' && str[j]!='S')
{
count=2;
}
if(str[j]=='A' || str[j]=='D' || str[j]=='W' || str[j]=='S'){
count++;
}
tempj=j;
}
if(count>=2)
break;
if(str[tempj]=='A')
{
for(int k=tempj+1;k<tempi;k++)
{
dx+=-(str[k]-'0')*pow(10,tempi-k-1);
}
}
if(str[tempj]=='D')
{
for(int k=tempj+1;k<tempi;k++)
{
dx+=(str[k]-'0')*pow(10,tempi-k-1);
}
}
if(str[tempj]=='W')
{
for(int k=tempj+1;k<tempi;k++)
{
dy+=(str[k]-'0')*pow(10,tempi-k-1);
}
}
if(str[tempj]=='S')
{
for(int k=tempj+1;k<tempi;k++)
{
dy+=-(str[k]-'0')*pow(10,tempi-k-1);
}
}
}else
continue;
}
x=dx;
y=dy;
cout<<x<<","<<y<<endl;
}
return 0;
}
18.识别有效IP地址和掩码并进行分类统计
题目描述:
请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。
思路分析:到最后这一题我也没看懂,主要不知道 这一题的标准是是是什么,然后通过看别
人通过的代码,大体懂了一些,然后主要学习到了string和int 两个类型之间转换的方式
主要通过 atoi(str.c_str())函数实现string到int 类型的转换(其中c_str()是将string 转
为 char* 类型)。然后是string这个数据结构中substr函数的应用,str.substr(子串开始
的位置,子串的长度),还有一个就是string数据结构find函数的应用,str.find(' ~') 发
现字符在原字符串中的位置。
还有一个有疑问的地方就是自己写了一个函数什么时候使用引用,什么时候不用使用引
用,这个地方比较疑惑。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void split(string& str, vector<string>& strs){
int pos=str.find('.');
while(pos>=0){
strs.push_back(str.substr(0, pos));
str=str.substr(pos+1, str.length()-pos-1);
pos=str.find('.');
}
strs.push_back(str);
}
bool checkNum(string& str){
if(str.size()==0 || str.size()>3)
return false;
for(int i=0; i<str.size(); i++){
if(str[i]<'0' || str[i]>'9')
return false;
}
int num=atoi(str.c_str());
if(num>=0 && num<=255)
return true;
return false;
}
bool checkIP(vector<string>& segs){
if(segs.size()!=4)
return false;
for(int i=segs.size()-1; i>=0; i--){
if(!checkNum(segs[i]))
return false;
}
//if(atoi(segs[0])==127)
// return false;
return true;
}
bool checkMask(vector<string>& segs){
if(segs.size()!=4)
return false;
bool start=false;
for(int i=0; i<segs.size(); i++){
if(!checkNum(segs[i]))
return false;
int num=atoi(segs[i].c_str());
if(start){
if(num!=0)
return false;
}else{
if(num!=255){
if(num==0 || num==128 || num==192 || num==224 || num==240 || num==248 || num==252 || num==254)
start=true;
else
return false;
}
}
}
if(atoi(segs[3].c_str())==255)
return false;
return true;
}
void classify(vector<string>& ip, vector<int>& counter){
int n1=atoi(ip[0].c_str());
int n2=atoi(ip[1].c_str());
if(n1>=1 && n1<=126){
if(n1==10)
counter[6]++;
counter[0]++;
}else if(n1>=128 && n1<=191){
if(n1==172 && n2>=16 && n2<=31)
counter[6]++;
counter[1]++;
}else if(n1>=192 && n1<=223){
if(n1==192 && n2==168)
counter[6]++;
counter[2]++;
}else if(n1>=224 && n1<=239)
counter[3]++;
else if(n1>=240 && n1<=255)
counter[4]++;
}
int main(){
vector<int> counter(7, 0);
int W=0, P=0;
string str;
while(cin>>str){
int pos=str.find('~');
string ip=str.substr(0, pos);
string mask=str.substr(pos+1, str.length()-pos-1);
vector<string> ip_segs, mask_segs;
split(ip, ip_segs);
split(mask, mask_segs);
if(!checkIP(ip_segs) || !checkMask(mask_segs))
counter[5]++;
else
classify(ip_segs, counter);
}
cout<<counter[0]<<" "<<counter[1]<<" "<<counter[2]<<" "<<counter[3]<<" "<<counter[4]<<" "<<counter[5]<<" "<<counter[6]<<endl;
return 0;
}
19.简单错误记录
题目描述:
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
思路分析:
这一题很奇怪,明明我输出的内容和对应的输出是一样的,但是还是没有通过,但是代码还是要贴出来的。通过这一题,学到了很多关于string类型吧函数的使用方法,以及一些特殊的关键字。
比如: string 的rfind函数:
就是发现字符串中指定字符所在最后一个位置的函数,通过这个函数你可以方便的找到
最后一次出现该字符的位置。
string类型的substr函数:
substr(pos),就是表示直接从pos位置向后的子字符串,还有一种表示方式是
substr(pos,length),表示从pos位置向后length距离的子字符串。
结构体的使用:
结构体最早接触是在c语言中,当时学习学的也是稀里糊涂,纯粹为了考试,并没有真
正想着如何取用。这一题中结构通过将两个判别数据以及一个存储数据放进来。并且实
现了运算符重载(这让我非常惊讶,结构体竟然能够运算符重载!!!) 还有一个让我
非常惊讶的就是结构体,竟然能和数据类型一样存在vecotr里面!!!直接就是一种数
据类型。其中结构体的变量赋值直接就是在结构体里面构造初始化函数和类的写法一
样。
vector查询相同变量内容:
可能这里我的话没说清楚,意思就是查询一个vector类型存储的内容里面有没有我们想
要的内容。这个查找方法是 auto res=find(myvec.begin(),myvec.end(),temp);
如果res==myvec.begin()就说明这个里面不存在,我们想找的temp。
其中res的类型,也可以是vector<erroNode>::iterator 就是一个指针类型,查找元素用
的。
贴代码:
#include<bits/stdc++.h>
using namespace std;
string getFileName(string path){
int pos=path.rfind('\\');
return path.substr(pos+1);
}
string modifyName(string name){
if(name.size()>16){
name=name.substr(name.size()-16);
}
return name;
}
struct ErrRecord{
string file;
int lineNo;
int count;
ErrRecord(string file,int lineNo){
this->file=file;
this->lineNo=lineNo;
count=1;
}
bool operator ==(const ErrRecord &a){
return (file== a.file) && (lineNo == a.lineNo);
}
};
int main(){
string file;
int lineNo;
vector<ErrRecord>myvec;
while(cin>>file>>lineNo){
ErrRecord record(getFileName(file),lineNo);
auto res=find(myvec.begin(),myvec.end(),record);
if(res==myvec.end()){
myvec.push_back(record);
}else{
res->count++;
}
}
int count=0;
for(auto item:myvec){
if(count+8 >=myvec.size()){
cout<<modifyName(item.file)<<" "<<item.lineNo<<" "<<item.count<<endl;
}
count++;
}
return 0;
}
20.密码验证合格程序
题目描述:
密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有相同长度超2的子串重复
说明:长度超过2的子串
思路分析:
这一题思路还是比较简单的,就是将三个条件进行判断就行了,开始还在为自己一遍通过,感觉沾沾自喜,后来看到了大神的AC,感觉自己还是个老实人,没有将效率进一步提高。其实判断子字符串完全可以只判断三个长度的子字符串,因为大于三个长度的子字符串完全是不用对比的。
老实人的代码:
#include<bits/stdc++.h>
using namespace std;
//写一个函数判断符号的种类
bool modifyNote(string str){
vector<int>count(4,0);
int zero_num=0;
for(int i=0;i<str.length();i++){
if(str[i]>='A' && str[i]<='Z')
{
count[0]++;
}else if(str[i]>='a' && str[i]<='z')
{
count[1]++;
}else if(str[i]>='0' && str[i]<='9')
{
count[2]++;
}else
{
count[3]++;
}
}
for(int i=0;i<4;i++)
{
if(count[i]==0)
zero_num++;
}
if(zero_num<=1)
return false;
else
return true;
}
//写一个函数用来判断长度超过2的子串 是否有重复的子字符串
//返回true 说明有相同的子字符串 返回false 则说明没有相同的子字符串。
bool substr_judge(const string str ){
string sub_str;
for(int i=0;i<str.length();i++){
for(int j=3;j<str.length();j++){
sub_str=str.substr(i,j);
//开始进行对比
for(int k=i+1;k<(str.length()-j);k++){
if(sub_str==str.substr(k,j))
return true;
}
}
}
return false;
}
int main(){
string str;
while(cin>>str){
if(str.length()<=8)
{
cout<<"NG"<<endl;
}else if(substr_judge(str)){
cout<<"NG"<<endl;
}else if(modifyNote(str))
cout<<"NG"<<endl;
else
cout<<"OK"<<endl;
}
return 0;
}
21.简单密码
题目描述:
假设渊子原来一个BBS上的密码为zvbo9441987,为了方便记忆,他通过一种算法把这个密码变换成YUANzhi1987,这个密码是他的名字和出生年份,怎么忘都忘不了,而且可以明目张胆地放在显眼的地方而不被别人知道真正的密码。
思路分析:
这一题不难,但是还是停留了好长时间,这主要是因为,遇到一个很坑的一个东西,就是你在if语句判断的时候,
能用if-elseif就尽量用,别用if-if 不然华为OJ很容易出错!!!
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
//变换主要针对于大小写字母 其他都不变
string str;
while(cin>>str){
int num=('a'-'A')+1;
for(int i=0;i<str.length();i++){
if(str[i]=='Z')
str[i]='a';
else if(str[i]>='A' && str[i]<'Z'){
str[i]=(char)(str[i]+num);
}else if(str[i]>='a' && str[i]<='z'){
switch(str[i]){
case 'a':
case 'b':
case 'c':
{ str[i]='2';
break;
}
case 'd':
case 'e':
case 'f':
{
str[i]='3';
break;
}
case 'g':
case 'h':
case 'i':
{
str[i]='4';
break;
}
case 'j':
case 'k':
case 'l':
{
str[i]='5';
break;
}
case 'm':
case 'n':
case 'o':
{
str[i]='6';
break;
}
case 'p':
case 'q':
case 'r':
case 's':
{
str[i]='7';
break;
}
case 't':
case 'u':
case 'v':
{
str[i]='8';
break;
}
case 'w':
case'x':
case 'y':
case 'z':
{
str[i]='9';
break;
}
}
}
}
cout<<str<<endl;
}
return 0;
}
22.汽水瓶
题目描述:
有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝?
思路分析:
这一题一遍过,掌握了规律真的很简单。然后这个规律是我猜的。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int num;
while(cin>>num){
if(num==0)
break;
num=num/2;
cout<<num<<endl;
}
return 0;
}
23.删除字符串中出现次数最少字符
题目描述:
实现删除字符串中出现次数最少的字符,若多个字符出现次数一样,则都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。
思路分析:
这一题逻辑难度不大,常规的一套思路走下来,基本就能完成,但是实现的时候,感觉难度还是有的,花了挺长时间的,感觉功力还是需要加强的
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
while(cin>>str){
int temp=20;
vector<int>pos;
vector<int>counter(26,0);
for(int i=0;i<str.length();i++){
counter[str[i]-'a']++;
}
for(int i=0;i<26;i++){
if(counter[i]<=temp && counter[i]!=0){
temp=counter[i];
}
}
for(int i=0;i<str.length();i++){
if(temp==counter[str[i]-'a'])
continue;
else
cout<<str[i];
}
cout<<endl;
}
return 0;
}
24.数据分类处理
题目描述:
信息社会,有海量的数据需要分析处理,比如公安局分析身份证号码、 QQ 用户、手机号码、银行帐号等信息及活动记录。
采集输入大数据和分类规则,通过大数据分类处理程序,将大数据分类输出。
思路分析:
这一题也想了一种解决的思路出来,但是后来解决的方法越来越负责,直接就放弃了。 后来找了一种还算比较简单的,思路还比较类似的。然后讲讲主要是怎么实现的吧。主要就是利用
vector先存储主要的元素,然后利用set这种数据结构排序去重的属性,先存储R类,然后再将其元素存储到vector数据结构中,然后利用stringstream将int转为string类型,然后利用find函数,发现子字符串的话find返回值就是 string::npos,然后如果符合条件的就放进结果的向量里面并且技术
感悟:
int->string
采用stringstream temp, string str; temp<<int_num; temp>>str;
set数据结构
采用set数据结构可以直接进行排序去重,同时插入形式是insert();
vector类型
vector进行排序的函数sort(vec.begin(),vec.end());vector 进行整段插入采用
采用的是insert()函数,insert(result.end(),temp.begin(),temp.end());其中
insert(result.begin(),val),表示在最前面插入元素值
insert(result.end(),val),表示在最后插入元素。
string类型
string 类查找字符串中是否有子串可以通过find函数,str.find(substr),如果返回值是std::string::npos 则说明字符串中存在需要查找的子串。
同时回顾一下之前的rfind函数,就是发现字符串中指定字符所在最后一个位置的函数,通过这个函数你可以方便的找到最后一次出现该字符的位置。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
vector<int>I(n);
for(int i=0;i<n;i++){
cin>>I[i];
}
int m;
cin>>m;
set<int>temp;
for(int i=0;i<m;i++){
int a;
cin>>a;
temp.insert(a);
}
vector<int>R;
set<int>::iterator iter=temp.begin();
while(iter!=temp.end()){
R.push_back(*iter);
++iter;
}
sort(R.begin(),R.end());
vector<int>result;
for(int i=0;i<R.size();i++){
stringstream ss1;
string str1;
ss1<<R[i];
ss1>>str1;
int ret=0;
vector<int>temp_result;
for(int j=0;j<n;j++){
stringstream ss;
string str;
ss<<I[j];
ss>>str;
size_t found=str.find(str1);
if(found!=std::string::npos){
temp_result.push_back(j);
temp_result.push_back(I[j]);
ret++;
}
}
if(ret){
result.push_back(R[i]);
result.push_back(ret);
result.insert(result.end(),temp_result.begin(),temp_result.end());
}
}
result.insert(result.begin(),result.size());
for(int i=0;i<result.size()-1;i++){
cout<<result[i]<<" "<<endl;
}
cout<<result[result.size()-1]<<endl;
}
return 0;
}
25.字符串排序
题目描述:
写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
样例:
输入:
A Famous Saying: Much Ado About Nothing(2012/8).
输出:
A aaAAbc dFgghh : iimM nNn oooos Sttuuuy (2012/8).
思路分析:
其实这一题总有一种一眼看穿的感觉,总有种一下子就能做出来的感觉,但是 看了好久还是没有进展,后来看看别人的做法,发现其实初始的想法还是已经和解决方案还是很近了。但是没有坚持下去。可惜。
但是需要注意的地方还是有很多的。
比如vector<char>temp 变量的设置,需要将vector里面的类型设置为char不然无法进行push_back。
另外一个需要注意的地方就是核心,需要将从1-26个字母依次存储就是依次减去'a' 'A'之后对应的数字。
还有一个就是将排好顺序的字符串赋值给原来的字符串的地方需要注意。
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
string str;
vector<char>temp;
while(cin>>str){
temp.clear();
for(int i=0;i<26;i++){
for(int j=0;j<str.size();j++){
if(str[j]-'a'==i || str[j]-'A'==i){
temp.push_back(str[j]);
}
}
}
for(int i=0 ,j=0;i<str.size() && j<temp.size();i++){
if(str[i]>='a' && str[i]<='z' || str[i]>='A' && str[i]<='Z'){
str[i]=temp[j++];
}
}
cout<<str<<endl;
}
return 0;
}
相关文章推荐
- 华为机试训练做题总结(二)
- 华为机试训练做题总结(三)
- 2013年网易校招 邮件事业部 客户端工程师选做题总结
- 8.10-8.11训练总结
- 求职者说:成功应聘华为后的总结
- C++ 牛客网做题笔记【600题总结】
- 2017年10月12日训练总结
- 关于训练指南的第一章总结
- 图论训练总结
- 2013 暑假多校训练 6总结
- 并查集做题总结
- 华为超级技术大牛的十年经验总结
- 8.13-8.14训练总结
- lintcode做题总结, Sept 16
- 华为2018校招研发笔试编程题总结
- "巴卡斯杯" 中国大学生程序设计竞赛 - 女生专场训练总结【9/10】
- 《算法竞赛-训练指南》第二章-数论常用算法总结
- 2017年11月19日训练总结
- 第十二周训练总结(二)
- 7.7~7.9 NOIP训练总结