牛客华为机试题刷题笔记(二)
来源:互联网 发布:国密算法标准 编辑:程序博客网 时间:2024/06/16 21:52
所有代码都在github
11.数字颠倒
颠倒就是逆序,可以把数字to_string
一下然后再reserve
我的做法是按数字的方式处理,模10除10
#include <iostream>#include <string>using namespace std;int main(){ int n; while(cin>>n) { string str; while(n) { str+=to_string(n%10); n/=10; } cout<<str<<endl; } return 0;}
12.字符串翻转
利用STL逆向迭代器和构造函数搞定
#include <iostream>#include <string>using namespace std;int main(){ string n; while(getline(cin,n)) { string str(n.rbegin(),n.rend()); cout<<str<<endl; } return 0;}
13.句子逆序
"hello world"
变成"world hello"
这个要逆转两次,先对整个句子进行逆序 "dlrow olleh"
再逐个单词逆序 "world hello"
#include <iostream>#include <string>#include <sstream>#include <algorithm>using namespace std;int main(){ string line; while(getline(cin,line)) { string tmp(line.rbegin(),line.rend()); stringstream ss(tmp); string word; vector<string>words; while(ss>>word) { words.push_back(string(word.rbegin(),word.rend())); words.push_back(" "); } for(int i=0;i<words.size();++i) { if(i==words.size()-1) words[i].pop_back(); cout<<words[i]; } cout<<endl; } return 0;}
14.字串的连接最长路径查找
看完题目才知道是字符串字典序排序,直接上std::sort
也行
不过我用了优先级队列,这样的话复杂度应该低一些。 std::priority_queue
需要注意的是模板参数
#include <iostream>#include <string>#include <vector>#include <queue>using namespace std;int main(){ int n; priority_queue<string,vector<string>,greater<string> >q; string str; while(cin>>n) { for(int i=0;i<n;++i) { cin>>str; q.push(str); } while(!q.empty()) { cout<<q.top()<<endl; q.pop(); } } return 0;}
15.求int型正整数在内存中存储时1的个数
剑指offer上的题,有一个小小的trick吧,当然直接按位比较也行的
#include <iostream>using namespace std;int main(){ int n; while(cin>>n) { int count=0; while(n) { n&=(n-1); ++count; } cout<<count<<endl; }}
16.购物单
这应该是前20题里面最耗费我时间的一题了。
改进的0-1背包,先回顾一下0-1背包:
最朴素的0-1背包问题里面,只有拿和不拿两个选项
因此动规方程可以如下写:
其中
这题复杂在于要分情况讨论(主组件还是次要组件),然后套一下0-1背包即可
#include <iostream>#include <vector>#include <algorithm>using namespace std;int main(){ int n,m; while(cin>>n>>m) { vector<int>v(m+1);//value vector<int>p(m+1);//importance vector<int>q(m+1);//major or minor vector< vector<int> >dp(m+1,vector<int>(n+1));//dp //input for(int i=1;i<=m;++i) { cin>>v[i]>>p[i]>>q[i]; } for(int i=1;i<=m;++i) { for(int j=1;j<=n;++j) { if(!q[i])//major { if(v[i]<=j) { dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+v[i]*p[i]); } } else// minor { if(v[i]+v[q[i]]<=j) { dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+v[i]*p[i]); } } } }//end for cout<<dp[m][n]<<endl; }}
17.坐标移动
坐标移动有几个要素:
1.将输入的数据分割成一个个的命令,可以用stringstream
2.判断每个命令是否合法
3.对命令进行编码(方向和移动的数值)
本题的坑在于不要盲目使用std::stoi
,比如说遇到A10A
这样的非法输入, std::stoi
会尽可能的转换,也就是说stoi("10A")
将得到10,因此,
使用时需要判断,stoi
是否全部转换:
size_t index=0; auto res=std::stoi(response,&index); if(index==response.size())//完全转化 { op=res; } else// { return false; }
#include <iostream>#include <string>#include <sstream>#include <vector>using namespace std;bool is_valid(string s,int& op,int &pointer){ if(s.size()<2||s.size()>3) return false; char point=s[0]; if(point!='W'&&point!='S'&&point!='A'&&point!='D') return false; else if(point=='W') pointer=2; else if(point=='A') pointer=0; else if(point=='S') pointer=3; else //D pointer=1; string response=s.substr(1); // size_t index=0; auto res=std::stoi(response,&index); if(index==response.size()) { op=res; } else { return false; } return true;}int main(int argc,char **argv){ string input; while(getline(cin,input)) { stringstream ss(input); vector<string>steps; int x=0; int y=0; while(ss.good()) { string step; int op=-1; int pointer=-1; getline(ss,step,';'); if(is_valid(step,op,pointer)) { //op: 0 -A -x | 1 -D +x | 2 -W +y | 3 -S -y if(pointer==0) { x-=op; } else if(pointer==1) { x+=op; } else if(pointer==2) { y+=op; } else { y-=op; } }//end if } cout<<x<<","<<y<<endl; } return 0;}
18.识别有效的IP地址和掩码并进行分类统计
这题可以说是相当麻烦了,以至于我拿出了我压箱底的网络编程的技能。
每组数据表示一个IP和mask,比如192.168.1.1~255.255.255.0
题目要求堆这一组数据进行分类:
A、B、C、D、E、不合法的IP或者mask、私有IP
几个要考虑的地方:
1.判断IP和mask是否合法直接交给inet_pton
了,这里只是从物理角度判断是否合法。排除类似192.1..1或者255…这种情况
2.判断mask是否合法,mask有个特点就是高地址全为1,低地址都是0,例如11111111000000000000000000000000
网上有人通过计算出二进制形式再去判断是挺麻烦的,我有更好的办法:
对于一个mask来说,判断是否为合法的mask,可以这样做:
a) 取反 tmp=~mask
b) 取反+1 tmp2=tmp+1
c) 相与,如果为0,则说明mask合法
这个算法很容易验证。
3.在使用socket函数注意大小端存储问题
4.只有mask和ip都合法之后,才能统计ip的类型,这是个体力活,一堆if-else
5.一个IP既可以是A类也可以是private
#include <iostream>#include <string>#include <vector>#include <sstream>#include <algorithm>#include <iterator>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>using namespace std;bool judgemask(string mask,vector<int>&result){ struct sockaddr_in ss; int ret = inet_pton(AF_INET,mask.c_str(),&ss.sin_addr); if(ret!=1) { ++result[5]; return false; } unsigned int num=ss.sin_addr.s_addr; num=ntohl(num);// if(num==0||~num==0) { ++result[5]; return false; } unsigned int y=~num; unsigned int z=(y+1); if((y&z)==0) { return true; } else { ++result[5]; return false; }}void judgeip(string ip,bool mask,vector<int>&result){ if(mask==false) { return ; } struct sockaddr_in ss; int ret = inet_pton(AF_INET,ip.c_str(),&ss.sin_addr); if(ret!=1) { ++result[5]; } else {#if 1 stringstream ss(ip); string a1; string a2; getline(ss,a1,'.'); getline(ss,a2,'.'); int num=std::stoi(a1); int num2=std::stoi(a2); if(num>=1&&num<=126) { ++result[0]; if(num==10) ++result[6]; } else if(num>=128&&num<=191) { ++result[1]; if((num==172)&& (num2>=16&&num2<=31)) ++result[6]; } else if(num>=192&&num<=223) { ++result[2]; if((num==192)&&(num2==168)) ++result[6]; } else if(num>=224&&num<=239) ++result[3]; else if(num>=240&&num<=255) ++result[4];#endif }}int main(){ string str; //0 1 2 3 4 5 6 //A B C D E wrongIP/mask private vector<int>result(7); while(cin>>str) { int pos=str.find('~'); string ip=str.substr(0,pos); string mask=str.substr(pos+1); bool ret = judgemask(mask,result); judgeip(ip,ret,result); } adjacent_difference(result.begin(),result.end(),ostream_iterator<int>(cout), [](int x,int y){cout<<" ";return x;} ); cout<<endl; return 0;}
19.简单错误记录
题目的几个描述:
1.记录最多8条记录,意思就是,如果有很多错误记录,只打印最后8条
2.输出的时候如果文件名超过16个字符则只要16个字符
3.输入的文件名有路径,输出不带路径
另外只比较文件名,不考虑路径,也就是/tmp/zx.c和/opt/zx.c认为是同一个文件
#include <iostream>#include <string>#include <sstream>#include <unordered_set>#include <vector>#include <algorithm>using namespace std;struct record{ string num; string file; mutable int count; record(string n,string f):num(n),file(f),count(1){}};bool operator==(const struct record & X,const struct record & Y){ return (Y.num==X.num)&&(Y.file==X.file);}bool operator!=(const struct record & X,const struct record & Y){ return !(X==Y);}string getFileName(const string &input){ std::size_t found = input.find_last_of("/\\"); string file = input.substr(found+1);#if 0 if(file.size()>16) { file = file.substr(file.size() - 16); }#endif return file;}void outFile(string &file){ if(file.size()>16) { file = file.substr(file.size() - 16); }}int main(int argc,char **argv){ string input1; string input2; vector<record> records;#if 1 while(cin>>input1>>input2) { string file=getFileName(input1); struct record r(input2,getFileName(input1)); auto it = find(records.begin(),records.end(),r); if(it!=records.end()) { it->count++; } else { records.push_back(r); } } int idx=(records.size()>8)?(records.size()-8):0; for(int i = idx;i<records.size();++i) { outFile(records[i].file); cout<<records[i].file<<" "<<records[i].num<<" "<<records[i].count<<endl; }#endif return 0;}
20.密码验证合格程序
三个条件,前两个简单,第三个的意思就是
如果字符串中有重复子串,那么他们重复的数目不能超过2
也就是说"abcxxxabc"
这样的字符是不合法的
第三个条件我的做法比较蠢,从0开始每次挑长度为3的子串,然后在剩下的部分查找子串,复杂度比较高,网上看到有正则表达式的解法,不是很熟。
#include <iostream>#include <string>using namespace std;bool condition1(const string& s){ if(s.size()>8) return true; else return false;}bool condition2(const string& s){ int upper=0; int lower=0; int digit=0; int symbol=0; int cnt=0; for(int i=0;i<s.size();++i) { if(s[i]>='0'&&s[i]<='9') { digit=1; } else if(s[i]>='a'&&s[i]<='z') { lower=1; } else if(s[i]>='A'&&s[i]<='Z') { upper=1; } else { symbol=1; } } cnt=upper+lower+digit+symbol; return cnt>2?true:false;}bool condition3(const string& s){ for(int i=0;i<s.size()-2;++i) { string tmp=s.substr(i,3); string ss=s.substr(i+1); if(ss.find(tmp)!=string::npos) { return false; } } return true;}int main(){ string s; while(cin>>s) { if(condition1(s)&&condition2(s)&&condition3(s)) { cout<<"OK"<<endl; } else { cout<<"NG"<<endl; } } return 0;}
- 牛客华为机试题刷题笔记(二)
- 牛客华为机试题刷题笔记(一)
- 牛客华为机试题刷题笔记(三)
- 牛客华为机试题刷题笔记(四)
- 牛客华为机试题刷题笔记(五)
- 华为机试题(二)
- 华为java机试题整理(二)
- 华为历年机试题型总结系列(二)
- 华为机试题二括号的匹配
- 华为面试题二
- 华为机试题第三题
- 华为机试题(2)
- 华为机试题(3)
- 华为机试题(4)
- 华为机试题(5)
- 华为机试题(6)
- 华为机试题(7)
- 华为机试题 (1)
- JSP四种属性范围
- RocketMQ命令整理
- jQuery中对数组的值进行去重处理
- 开篇Markdonw
- jdk-ThreadPoolExecutor(三)---内部Worker和执行方法
- 牛客华为机试题刷题笔记(二)
- Spring框架
- HTML:利用F12进行程序调试,断点的清理以及添加事件监听
- codeforces 821 B Okabe and Banana Trees
- Mac OS 怎么用?
- 【Java】线程join方法
- 欢迎使用CSDN-markdown编辑器
- linux 中更改用户权限和用户组的命令实例--chmod,chgrp应用
- C++ 日常笔记(5)