算法学习——华为机考题库2(HJ11 - HJ20)
HJ11 数字颠倒
描述
输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001
数据范围: 0≤n≤2 30 −1
输入描述:
输入一个int整数
输出描述:
将这个整数以字符串的形式逆序输出
示例
代码解析
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main() {
int num;
cin>>num;
string myStr = to_string(num);
reverse(myStr.begin() , myStr.end());
cout<<myStr;
}
// 64 位输出请用 printf("%lld")
HJ12 字符串反转
描述
接受一个只包含小写字母的字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)
输入描述:
输入一行,为一个只包含小写字母的字符串。
输出描述:
输出该字符串反转后的字符串。
示例
代码解析
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main() {
string Str;
cin>>Str;
reverse(Str.begin(), Str.end());
cout<<Str;
}
// 64 位输出请用 printf("%lld")
HJ13 句子逆序
描述
将一个英文语句以单词为单位逆序排放。例如“I am a boy”,逆序排放后为“boy a am I”
所有单词之间用一个空格隔开,语句中除了英文字母外,不再包含其他字符
**数据范围:**输入的字符串长度满足 1≤n≤1000
注意本题有多组输入
输入描述:
输入一个英文语句,每个单词用空格隔开。保证输入只包含空格和字母。
输出描述:
得到逆序的句子
示例
代码解析
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main() {
string myStr;
getline(cin, myStr);
reverse(myStr.begin(), myStr.end());
// cout<<myStr<<endl;
int left = 0 , right = 0;
for(int right = 0 ; right < myStr.size() ; right++)
{
if(myStr[right] == ' ' )
{
reverse(myStr.begin() + left, myStr.begin() + right);
left = right + 1;
}
if(right == myStr.size()-1)
{
reverse(myStr.begin() + left, myStr.begin() + right + 1);
}
}
cout<<myStr;
}
// 64 位输出请用 printf("%lld")
HJ14 字符串排序
描述
给定 n 个字符串,请对 n 个字符串按照字典序排列。
数据范围: 1≤n≤1000 ,字符串长度满足 1≤len≤100
输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。
输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。
示例
代码解析
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
static bool cmp(string &s1 , string &s2)
{
return s1 < s2;
}
int main() {
int N;
cin>>N;
vector<string> myVec;
string tmp;
while(N--)
{
cin>>tmp;
myVec.push_back(tmp);
}
sort(myVec.begin(), myVec.end(), cmp);
for(int i = 0 ; i < myVec.size(); i++)
{
cout<< myVec[i]<<endl;
}
}
// 64 位输出请用 printf("%lld")
HJ15 求int型正整数在内存中存储时1的个数
描述
输入一个 int 型的正整数,计算出该 int 型数据在内存中存储时 1 的个数。
**数据范围:**保证在 32 位整型数字范围内
输入描述:
输入一个整数(int类型)
输出描述:
这个数转换成2进制后,输出1的个数
示例
代码解析
#include <iostream>
using namespace std;
int main() {
int num , result = 0;
cin>>num;
for(int i=0 ; i < 32 ; i++)
{
if((num&0x01 ) == 1 ) result++;
num = num>>1;
}
cout<<result;
}
// 64 位输出请用 printf("%lld")
HJ16 购物单
描述
王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
输入描述:
输入的第 1 行,为两个正整数N,m,用一个空格隔开:
(其中 N ( N<32000 )表示总钱数, m (m <60 )为可购买的物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q
(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)
输出描述:
输出一个正整数,为张强可以获得的最大的满意度。
示例
代码解析
#include<iostream>
#include<vector>
using namespace std;
int main(){
int M,N;
cin>>M>>N;
M/=10;
vector<vector<int>> price(N+1,vector<int>(3,0));
vector<vector<int>> value(N+1,vector<int>(3,0));
for(int i=1;i<=N;i++){
int a,b,c;
cin>>a>>b>>c;
if(c==0){
price[i][0]=a/10;
value[i][0]=b;
}
else{
if(price[c][1]!=0){
price[c][2]=a/10;
value[c][2]=b;
}
else{
price[c][1]=a/10;
value[c][1]=b;
}
}
}
vector<vector<int>> dp(N+1,vector<int>(M+1,0));
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
int a=price[i][0],b=value[i][0];
int c=price[i][1],d=value[i][1];
int e=price[i][2],f=value[i][2];
dp[i][j]=j>=a?max(dp[i-1][j-a]+a*b,dp[i-1][j]):dp[i-1][j];
dp[i][j]=j>=a+c?max(dp[i-1][j-a-c]+a*b+c*d,dp[i][j]):dp[i][j];
dp[i][j]=j>=a+e?max(dp[i-1][j-a-e]+a*b+e*f,dp[i][j]):dp[i][j];
dp[i][j]=j>=a+c+e?max(dp[i-1][j-a-e-c]+a*b+c*d+e*f,dp[i][j]):dp[i][j];
}
}
cout<<dp[N][M]*10<<endl;
return 0;
}
HJ17 坐标移动
描述
开发一个坐标计算工具, A表示向左移动,D表示向右移动,W表示向上移动,S表示向下移动。从(0,0)点开始移动,从输入字符串里面读取一些坐标,并将最终输入结果输出到输出文件里面。
输入:
合法坐标为A(或者D或者W或者S) + 数字(两位以内)
坐标之间以;分隔。
非法坐标点需要进行丢弃。如AA10; A1A; % ; YAD; 等。
下面是一个简单的例子 如:
A10;S20;W10;D30;X;A1A;B10A11;;A10;
处理过程:
起点(0,0)
-
A10 = (-10,0)
-
S20 = (-10,-20)
-
W10 = (-10,-10)
-
D30 = (20,-10)
-
x = 无效
-
A1A = 无效
-
B10A11 = 无效
-
一个空 不影响
-
A10 = (10,-10)
结果 (10, -10)
数据范围: 每组输入的字符串长度满足 1≤n≤10000 ,坐标保证满足 −2 31 ≤x,y≤2 31 −1 ,且数字部分仅含正数
输入描述:
一行字符串
输出描述:
最终坐标,以逗号分隔
示例
代码
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string myStr;
vector<string> date;
cin>>myStr;
int x =0 , y = 0;
string tmp ;
for(int i=0 ; i<myStr.size() ;i++)
{
if(myStr[i] == ';')
{
date.push_back(tmp);
tmp.clear();
}
else tmp += myStr[i];
}
char dir;
int lenght = 0;
for(int i=0 ; i<date.size() ;i++)
{
dir = date[i][0];
if(dir == 'A' ||dir == 'D' ||dir == 'W' ||dir == 'S')
{
tmp = date[i].substr(1,date[i].size() -1);
bool flag = true;
for(int x=0 ; x<tmp.size() ; x++ )
{
if( tmp[x] >= '0' && tmp[x] <= '9') {}
else
{
flag = false;
break;
}
}
if(flag == true)
{
lenght = stoi(tmp);
// cout<<dir<<lenght<<endl;
if(dir == 'A') x -= lenght;
else if(dir == 'D') x += lenght;
else if(dir == 'W') y += lenght;
else if(dir == 'S') y -= lenght;
}
}
}
cout<<x<<','<<y;
}
// 64 位输出请用 printf("%lld")
HJ18 识别有效的IP地址和掩码并进行分类统计
描述
请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。
所有的IP地址划分为 A,B,C,D,E五类
A类地址从1.0.0.0到126.255.255.255;
B类地址从128.0.0.0到191.255.255.255;
C类地址从192.0.0.0到223.255.255.255;
D类地址从224.0.0.0到239.255.255.255;
E类地址从240.0.0.0到255.255.255.255
私网IP范围是:
从10.0.0.0到10.255.255.255
从172.16.0.0到172.31.255.255
从192.168.0.0到192.168.255.255
子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
(注意二进制下全是1或者全是0均为非法子网掩码)
注意:
- 类似于【0...】和【127...】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时请忽略
- 私有IP地址和A,B,C,D,E类地址是不冲突的
输入描述:
多行字符串。每行一个IP地址和掩码,用~隔开。
请参考帖子https://www.nowcoder.com/discuss/276处理循环输入的问题。
输出描述:
统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。
示例
代码解析
#include<iostream>
#include<string>
#include<sstream>
#include<vector>
using namespace std;
bool judge_ip(string ip){
int j = 0;
istringstream iss(ip);
string seg;
while(getline(iss,seg,'.'))
if(++j > 4 || seg.empty() || stoi(seg) > 255)
return false;
return j == 4;
}
bool is_private(string ip){
istringstream iss(ip);
string seg;
vector<int> v;
while(getline(iss,seg,'.')) v.push_back(stoi(seg));
if(v[0] == 10) return true;
if(v[0] == 172 && (v[1] >= 16 && v[1] <= 31)) return true;
if(v[0] == 192 && v[1] == 168) return true;
return false;
}
bool is_mask(string ip){
istringstream iss(ip);
string seg;
unsigned b = 0;
while(getline(iss,seg,'.')) b = (b << 8) + stoi(seg);
if(!b) return false;
b = ~b + 1;
if(b == 1) return false;
if((b & (b-1)) == 0) return true;
return false;
}
int main(){
string input;
int a = 0,b = 0,c = 0,d = 0,e = 0,err = 0,p = 0;
while(cin >> input){
istringstream is(input);
string add;
vector<string> v;
while(getline(is,add,'~')) v.push_back(add);
if(!judge_ip(v[1]) || !is_mask(v[1])) err++;
else{
if(!judge_ip(v[0])) err++;
else{
int first = stoi(v[0].substr(0,v[0].find_first_of('.')));
if(is_private(v[0])) p++;
if(first > 0 && first <127) a++;
else if(first > 127 && first <192) b++;
else if(first > 191 && first <224) c++;
else if(first > 223 && first <240) d++;
else if(first > 239 && first <256) e++;
}
}
}
cout << a << " " << b << " " << c << " " << d << " " << e << " " << err << " " << p << endl;
return 0;
}
HJ19 简单错误记录
描述
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:
1、 记录最多8条错误记录,循环记录,最后只用输出最后出现的八条错误记录。对相同的错误记录只记录一条,但是错误计数增加。最后一个斜杠后面的带后缀名的部分(保留最后16位)和行号完全匹配的记录才做算是“相同”的错误记录。
2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;
3、 输入的文件可能带路径,记录文件名称不能带路径。也就是说,哪怕不同路径下的文件,如果它们的名字的后16个字符相同,也被视为相同的错误记录
4、循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准
**数据范围:**错误记录数量满足 1≤n≤100 ,每条记录长度满足 1≤len≤100
输入描述:
每组只包含一个测试用例。一个测试用例包含一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
输出描述:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开,如:
示例
代码解析
#include <algorithm>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<pair<string , int>> date;
string tmpName;
int num;
while (cin >> tmpName >> num) {
deque<char> tmDeq;
for(int i=tmpName.size()-1 ; i > 0 ; i--)
{
if(tmpName[i] == '\\' ||tmpName.size() - i > 16 ) break;
tmDeq.push_front(tmpName[i]);
}
tmpName.assign(tmDeq.begin(), tmDeq.end());
tmpName += ' ';
tmpName += to_string(num) ;
// cout<<"tmpName "<<tmpName<<endl;
bool flag = false;
for(int i=0 ; i <date.size() ; i++)
{
if(date[i].first == tmpName)
{
date[i].second++;
flag = true;
}
}
if(flag == false) date.push_back({tmpName , 1});
}
if(date.size() > 8)
{
for(int i=date.size()-8 ; i<date.size() ; i++)
cout<<date[i].first << ' '<<date[i].second<<endl;
}else
{
for(int i=0 ; i<date.size() ; i++)
cout<<date[i].first << ' '<<date[i].second<<endl;
}
date.clear();
}
// 64 位输出请用 printf("%lld")
HJ20 密码验证合格程序
描述
密码要求:
1.长度超过8位
2.包括大小写字母.数字.其它符号,以上四种至少三种
3.不能有长度大于2的包含公共元素的子串重复 (注:其他符号不含空格或换行)
数据范围:输入的字符串长度满足 1≤n≤100
输入描述:
一组字符串。
输出描述:
如果符合要求输出:OK,否则输出NG
示例
代码解析
#include <iostream>
#include <string>
using namespace std;
string cheak(string &tmp)
{
int flag[4] = {0,0,0,0};
if(tmp.size() <= 8) return "NG";
for(int i=0 ; i <tmp.size() ; i++)
{
if(tmp[i] >= 'A' && tmp[i] <= 'Z') flag[0] = 1;
else if(tmp[i] >= 'a' && tmp[i] <= 'z') flag[1] = 1;
else if(tmp[i] >= '0' && tmp[i] <= '9') flag[2] = 1;
else flag[3] = 1;
}
int count = 0;
for(int i=0 ; i<4 ; i++)
if(flag[i] == 1) count++;
if(count < 3) return "NG";
for(int i=0 ; i<tmp.size() ; i++)
{
for(int j=i+3 ; j<tmp.size() ; j++)
{
if(tmp[i] == tmp[j] && tmp[i+1] == tmp[j+1] && tmp[i+2] == tmp[j+2])
return "NG";
}
}
return "OK";
}
int main() {
string tmp;
while (cin >> tmp )
{
cout << cheak(tmp) << endl;
}
}
// 64 位输出请用 printf("%lld")