目录
1.剑指Offer
面试题54:二叉树的第k个节点
题目描述:给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
思路:中序遍历+递归
代码:
class Solution {
public:
TreeNode* KthNode(TreeNode* pRoot, int k)
{
if(pRoot==nullptr||k<=0){
return nullptr;
}
return KthNodeCore(pRoot,k);
}
TreeNode* KthNodeCore(TreeNode* pRoot, int &k)
{
TreeNode* target=nullptr;
if(pRoot->left!=nullptr){
target=KthNodeCore(pRoot->left,k);
}
if(target==nullptr){
if(k==1){
return pRoot;
}
k--;
}
if(target==nullptr&&pRoot->right!=nullptr){
target=KthNodeCore(pRoot->right,k);
}
return target;
}
};
面试题40:最小的k个数
题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路:红黑树实现,采用multiset
代码:
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
int len=input.size();
if(len<=0||k>len){
return vector<int>();
}
multiset<int,greater<int>> leastNumbers;
vector<int>::iterator iter=input.begin();
for(;iter!=input.end();iter++){
if(leastNumbers.size()<k){
leastNumbers.insert(*iter);
}
else{
multiset<int,greater<int>>::iterator greatest=leastNumbers.begin();
if(*iter<(*leastNumbers.begin())){
leastNumbers.erase(greatest);
leastNumbers.insert(*iter);
}
}
}
return vector<int>(leastNumbers.begin(),leastNumbers.end());
}
};
解析:
C++ multiset通过greater、less指定排序方式,实现最大堆、最小堆功能
参考:https://www.cnblogs.com/ficow/p/10045777.html
3.华为机试题
例1:购物单
题目描述:
王强今天很开心,公司发给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 ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。
输入描述:
输入的第 1 行,为两个正整数,用一个空格隔开:N m
(其中 N ( <32000 )表示总钱数, m ( <60 )为希望购买物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q
(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)
输出描述:
输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值( <200000 )。
示例1
输入
1000 5 800 2 0 400 5 1 300 5 1 400 3 0 500 2 0
输出
2200
思路:动态规划
代码:
#include <iostream>
#include <string.h> //包含memset函数
using namespace std;
int main(){
int v[61];
int dp[61][32001];
int q[61];
int vp[61];
int N,m;
while(cin>>N>>m){
for(int i=0;i<61;i++){
memset(dp[i],0,sizeof(dp[i]));
}
int tmp;
for(int i=1;i<=m;i++){
cin>>v[i]>>tmp>>q[i];
vp[i]=v[i]*tmp;
}
for(int i=1;i<=m;i++){
for(int j=1;j<=N;j++){
if(q[i]==0){
if(v[i]<=j){
dp[i][j]=max(dp[i-1][j-v[i]]+vp[i],dp[i-1][j]);
}
}
else{
if(v[i]+v[q[i]]<=j){
dp[i][j]=max(dp[i-1][j-v[i]]+vp[i],dp[i-1][j]);
}
}
}
}
cout << dp[m][N] << endl;
}
return 0;
}
例2:坐标移动
题目描述:
开发一个坐标计算工具, 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
输入
A10;S20;W10;D30;X;A1A;B10A11;;A10;
输出
10,-10
代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main(){
string str;
while(getline(cin,str)){
vector<string> v;
int len=str.length();
int x=0;
int y=0;
int keep=0;
for(int i=0;i<len;i++){
if(str[i]!=';'){
keep++;
continue;
}
v.push_back(str.substr(i-keep,keep)); //取keep长度的子串
keep=0;
}
for(int i=0;i<v.size();i++){
int num=0;
if(v[i].length()==3&&(v[i][1]>='0'&&v[i][1]<='9')&&(v[i][2]>='0'&&v[i][2]<='9')){
num=(v[i][1]-'0')*10+(v[i][2]-'0');
}
if(v[i].length()==2&&(v[i][1]>='0'&&v[i][1]<='9')){
num=v[i][1]-'0';
}
switch(v[i][0]){
case 'A':x-=num;break;
case 'D':x+=num;break;
case 'W':y+=num;break;
case 'S':y-=num;break;
default:break;
}
}
cout << x << "," << y << endl;
}
return 0;
}
例3:识别有效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就是一个非法的掩码)
本题暂时默认以0开头的IP地址是合法的,比如0.1.1.2,是合法地址
输入描述:
多行字符串。每行一个IP地址和掩码,用~隔开。
输出描述:
统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。
示例1
输入
10.70.44.68~255.254.255.0 1.0.0.1~255.0.0.0 192.168.0.2~255.255.255.0 19..0.~255.255.255.0
输出
1 0 1 0 0 2 1
代码:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
int stringtoint(string str){
stringstream ss;
int a;
ss<<str;
ss>>a;
return a;
}
vector<int> toint(string str){
string tmp;
vector<int> res;
int num;
for(int i=0;i<str.length();i++){
if(str[i]!='.'){
tmp.push_back(str[i]);
}
else{
num=stringtoint(tmp);
tmp.clear();
res.push_back(num);
}
}
num=stringtoint(tmp);
res.push_back(num);
return res;
}
bool maskisvalid(vector<int> res){
if(res.size()!=4){
return false;
}
if(res[0]==255){
if(res[1]==255){
if(res[2]==255){
if(res[3]==254||res[3]==252||res[3]==248||res[3]==240||res[3]==224||res[3]==192||res[3]==128||res[3]==0){
return true;
}
else{
return false;
}
}
else{
if(res[2]==254||res[2]==252||res[2]==248||res[2]==240||res[2]==224||res[2]==192||res[2]==128||res[2]==0){
if(res[3]==0){
return true;
}
else{
return false;
}
}
}
}
else{
if(res[1]==254||res[1]==252||res[1]==248||res[1]==240||res[1]==224||res[1]==192||res[1]==128||res[1]==0){
if(res[2]==0&&res[3]==0){
return true;
}
else{
return false;
}
}
}
}
else{
if(res[0]==254||res[0]==252||res[0]==248||res[0]==240||res[0]==224||res[0]==192||res[0]==128){
if(res[1]==0&&res[2]==0&&res[3]==0){
return true;
}
else{
false;
}
}
}
return false;
}
int main(){
string str;
int* res=new int[7]; //结果
for(int i=0;i<7;i++){
res[i]=0;
}
while(cin>>str){
string ipstr,maskstr;
vector<int> ip,mask;
int i=0;
for(;str[i]!='~';i++){
ipstr.push_back(str[i]); //得到ip字符串
}
i++;
for(;i<str.length();i++){
maskstr.push_back(str[i]); //得到mask字符串
}
ip=toint(ipstr);
mask=toint(maskstr);
if(maskisvalid(mask)){ //mask有效
if((ip[1]>=0&&ip[1]<=255)&&(ip[2]>=0&&ip[2]<=255)&&(ip[3]>=0&&ip[3]<=255)){
if(ip[0]>=1&&ip[0]<=126){ //A类
res[0]++;
if(ip[0]==10){
res[6]++;
}
}
else if(ip[0]>=128&&ip[0]<=191){ //B类
res[1]++;
if(ip[0]==172&&(ip[1]>=16&&ip[0]<=31)){
res[6]++;
}
}
else if(ip[0]>=192&&ip[0]<=223){ //C类
res[2]++;
if(ip[0]==192&&ip[1]==168){
res[6]++;
}
}
else if(ip[0]>=224&&ip[0]<=239){ //D类
res[3]++;
}
else if(ip[0]>=240&&ip[0]<=255){ //D类
res[4]++;
}
} //ip[1]
}//isvalid
else{
res[5]++;
}
} //while
cout << res[0] << " " << res[1] << " " << res[2] << " " << res[3] << " " << res[4] << " " << res[5] << " " << res[6] << endl;
return 0;
}