2013华为机试与面试题集锦

2013华为机试与面试题汇总

都是在网上找的自己总结的。。。


 
1.) 字母大小写反转
这到题没什么可说的,只是我很久没写这样要IO输入输出的代码,当时看到华为的提示纸条上写着“只能使用stdin方式输入”,还愣了一会:一定是我打开方式不对,什么时候有了一个stdin的输入函数?难道我又学艺不精了……后面才反应过来,直接按英文字面意思理解为“只能使用标准输入方式”就好了。好了,言归正传,回到这道题,至少可以用以下两种方式:
C++ STL库string中 有  isupper , islower , toupper ,tolower 函数
通过 +/- ('a'-'A'+0)
(2.) n个人围成一圈,从第1个人开始报数,每报到第m个人,则其出局,求最后出局的人的初始序号。
        
        第1种方法,我当时是用了个状态表来记录这人有没有出局,没出局则报数计数器加1并玩下走,碰到第m个报数号则更新状态为已出局,碰到队伍最末则重新移动到队首。

 
#include <iostream>
#define N 4
#define M 3
using namespace std;
int *man = NULL;
int JosephusSol_statusTab(int n,int m)
{
    int sn=0 , pos = 0 ,loop_pos=0;
    do
    {
        if( man[pos] == 0 ){//此人未出局
            loop_pos++;
            if(loop_pos == m){//找到一轮报数的出局者
                sn++;
                man[pos] = sn ; // 标记出局序号
                loop_pos = 0;
            }
        }
        pos ++ ;
        if(pos==n)
            pos = 0;
    }while(sn!=n);
    return pos;
}


int main()
{
    int sn=0 , pos = 0 ,loop_pos=0;
    man = new int [N];
    for(int i=0;i<N;i++)
        man[i] = 0;
    pos = JosephusSol_statusTab(N,M);
    cout << pos <<endl ;
    if(man != 0)
        delete [] man;
    return 0;
}
    
        第2种方法是双向链表,技术面面试的时候,面试官就考了我这一题,在纸上快速写代码的能力还是有所欠缺。


        第3种方法是递归,
第0次报数(即初始排列状态)如下:
1
2
……
 
 
n
第1次报数到m,剔除后的序列为:
m+1
m+2

n
1
2

m-1
         重新编号的话为:  
1
2

n-m
n-m+1
n-m+2

n-1
     设f(n,m)为n个人的队伍,剔除报数人m,最后留下的人的序号;f(n-1,m)为n-1个人的队伍,剔除报数人m,最后留下的人的序号。则有:
          
考虑到第1次报数后的序列号n的情况,可得到统一的公式为:
 
这就是这个问题的一个递归公式,实现代码如下:
#include < iostream >
using namespace std;
 
int JosephusSol_mathRecursion( int n, int m)
{
     if (n == 1 )
         return 1 ;
     else
         return (JosephusSol_mathRecursion(n - 1 ,m) + m - 1 ) % n + 1 ;
}
int main()
{
    cout << JosephusSol_mathRecursion( 4 , 3 ) << endl ;
     return 0 ;
}
3.两段长度为1-5000变换的单词word1,word2,设计一个字母权重分配方案:该方案中不区分大小写字母;该方案A-Z的字母唯一对应一个1-26的数;该方案满足word1的字母权重和与word2的字母权重和的差值最大 。
这个问题是实质是比较单词,剔除相同的部分,看哪个剩余部分多,剩余多的单词部分再进行一个字母频率从大到小排列,频率最高的给最大的权重——26,频率低一些的依次给剩余的最大权重;剩余的单词部分再进行一个字母频率也是从大到小排列,只不过频率最高的给最小的权重——1,频率高一些的依次给剩余的最小权重。
至于实现,若是先直接比较单词,再字母频率统计,工作量有点大。可以考虑直接用 字母表A-Z为索引,将单词装换为字母表A-Z的编码(更形象点,即将杂乱的单词变成一个26进制数,当然这样没有包含单词的全部信息——字母在单词中的排序就不知道,所以可以装换成26个节点,每个节点还含有一个排序数组,如单词daddy,相对应的d节点下就含有一个size为3的数组,有sn['d'][3]={0,2,3}。当然本题只需要一个量就是size['d']=3。)

#include <iostream>
#include <string>
#include <vector>
 
using namespace std;
int main()
{
    string str1("mother"),str2("father");
    // string str1,str2;
    // cin  >> str1 >> str2;
    size_t i = 0 ,j =0;
 
    vector<int> status1(26,0);
    vector<int> status2(26,0);
    vector<int> diff(26,0);
    vector<int> negative(26,0);   
    vector<int> positive(26,0);   
    int cntNeg = 0 , cntPos = 0;
    for( i = 0; i< str1.size(); i++)
    {
        char c = str1[i];
        if( 'a'<=c && c <= 'z' ){
            status1[c -'a' + 0]++;
        }
        if( 'A'<=str1[i] && str1[i] <= 'Z' ){
            status1[c-'A'+ 0]++;
        }
    }
    for( i = 0; i< str2.size(); i++)
    {
        char c = str2[i];
        if( 'a'<=str2[i] && str2[i] <= 'z' ){
            status2[c -'a' + 0]++;
        }
        if( 'A'<=str2[i] && str2[i] <= 'Z' ){
            status2[c -'A' + 0]++;
        }
    }
 
    for( i = 0; i< 26; i++){
        diff[i] = status2[i] - status1[i];
        if(diff[i]<0)
        {
            negative[i] = -diff[i];
            cntNeg += negative[i];
        }
        else
        {
            positive[i] = diff[i];
            cntPos += positive[i];
        }
    }
    for( i = 0; i< 26; i++)
        cout << ' '<< status1[i] <<' '<< status2[i] <<' '<< diff[i] << endl;
 
    int tmp= 0;
    int a[26],b[26];
    cout << ' '<< cntNeg <<' '<< cntPos;
    for( i = 0 ; i < 26;i++ )
    {
        a[i] = 26-i;
        b[i] = i+1;
    }
 
    for( i = 0 ; i < 26;i++ )
        for(j = i+1 ;j <26;j++)
        {
            if( negative[i] < negative[j] ){
                tmp = negative[i];
                negative[i] = negative[j];
                negative[j] = tmp;
            }
        }
    for( i = 0 ; i < 26;i++ )
        for(j = i+1 ;j <26;j++)
        {
            if( positive[i] < positive[j] ){
                tmp = positive[i];
                positive[i] = positive[j];
                positive[j] = tmp;
            }
        }
 
    int out=0 , large = 0, small =0 ;
    for( i = 0 ; i < 26;i++ )
    {
        if( cntNeg >= cntPos  ) {
            large += a[i]*negative[i];   
            small += b[i]*positive[i];
        }           
        else{
            large += a[i]*positive[i];
            small += b[i]*negative[i];
        }
    }
 
    out = large - small;
    cout << out ;
 
    return 0;
}



2

华为2013年在长沙的一个机试题是判断润年。年份要求是四位数。
输入样例:
2012
2122
afdsfa
22.33
输出样例:
YES
NO
ERROR
 

我的答案是:
 
Java代码  收藏代码
package cn.william;  
  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
  
import javax.swing.JFrame;  
import javax.swing.JLabel;  
import javax.swing.JTextField;  
  
/** 
 * 华为2013年机试题:求润年 
 * @author william 
 * 
 */  
public class Test extends JFrame{  
    private JLabel lable;  
    private JTextField field;  
      
    public static void main(String[] args){  
        Test frame = new Test();  
        frame.init();  
    }  
      
    public void init(){  
        this.setSize(400, 250);  
        this.setLayout(null);  
        lable = new JLabel("请输入年份:");  
        field = new JTextField();  
        lable.setBounds(140, 90, 120, 30);  
        field.setBounds(140, 120,120, 30);  
        this.add(field);  
        this.add(lable);  
        this.setVisible(true);  
          
        field.addActionListener(new ActionListener() {  
              
            @Override  
            public void actionPerformed(ActionEvent e) {  
                String year = field.getText().toString();  
                if(year.length() != 4){  
                    System.out.println("ERROR");  
                    return;  
                }  
                int y = 0;  
                  
                try{  
                    y = Integer.parseInt(year);  
                }catch(Exception ex){  
                    System.out.println("ERROR");  
                    return;  
                }  
                  
                  
                check(y);  
            }  
        });  
    }  
      
    private void check(int year){  
          
        if(year == 0){  
            System.out.println("ERROR");  
            return;  
        }  
          
        if(year % 100 == 0){  
            if(year % 400 == 0){  
                System.out.println("YES");  
            }else{  
                System.out.println("NO");  
            }  
        }else{  
            if(year % 4 == 0){  
                System.out.println("YES");  
            }else{  
                System.out.println("NO");  
            }  
        }  
    }  
  
}  
 
 
顺便复习一下java异常的知识。
异常定义:能让程序意外中断运行的指令流。
java异常类的结构如下


Throwable包括了一切的异常。ERROR是JVM的异常,不可以用我们的代码处理。Exception是我们程序中可能出现的异常,可以处理。
RuntimeException和Exception的关系:
RuntimeException继承自Exception,RuntimeException和它的子类可以不用try catch进行处理。
 
Java代码  收藏代码
ry{  
    y = Integer.parseInt(year);  
}catch(Exception ex){  
    System.out.println("ERROR");  
    return;  
}  
 
其实这里 Integer.parseInt(year) 可能会抛出NumberFormatException的,但是eclipse并没有提示这句代码需要处理异常,因为NumberFormatException是RuntimeException的子类。
当然因为RuntimeException是Exception的子类,所以,也可以用try catch来处理。




3

之前投了华为的实习生,昨天让去参加“华为编程大赛”机试。就一个题,在网吧上机,时间30分钟,题目如下:
17进制转成10进制,输入是数字跟大写字母。例如输入G、11、FF,分别输出16、18、270


参考代码如下:
void main()
{
        string str;
        cin>>str;
        int i=0;
        int num=0;//保存转换后数字
        int factor=1;
        bool sign=1;//用来标志输入字符串是否非法
        int len=str.size();


        for (i=0;i<len;i++)
        {
                if (str[i]>='0' && str[i]<='9')
                {
                        
                        num=num*factor+(str[i]-'0');
                        factor*=17;
                }
                else if (str[i]>='A' && str[i]<='G')
                {
                        
                        num=num*factor+(str[i]-'A'+10);
                        factor*=17;
                }
                else
                {
                        sign=0;
                        break;
                }
        }
        if (sign)
                cout<<num<<endl;
        else
                cout<<"Error Input!"<<endl;


}



4

一:通过键盘输入任意一个字符串序列,字符串可能包含多个子串,子串以空格分隔,请编写一个程序,自动分离出各个子串,并使用’,’将其分隔,并且在最后也补充一个’,’,并将子串存储。
如果输入”abc def ghi d”,结果将是abc,def,gh,i,d
要求实现函数
Void DivideString(const char *pInputStr,long IinputLen,char *pOutputStr);
输入:pInputStr:输入字符串
IinputLen:输入字符串的长度
输出:pOutputStr:输出字符串,字符串已开辟好,与输入字符串等长
注意:只需要完成该函数功能算法,中间不需要有任何IO的输入输出



解,首先去掉字符串前面开始的空格,然后遍历字符串,遇到空格时,将标志设为真,先不处理,等下次时循环时,若标志为真,则在字符前加一,号即可




oid DivideString(const char *pInputStr,long IinputLen, char *OutputStr)
{
    int cnt=0,i=0;//计数
    bool flag=false;
    while(pInputStr[i]==' ')//去掉前面的空格
        i++;
    for(;i<IinputLen;i++)
    {
        if(pInputStr[i]==' ')
        {
            flag=true;
            continue;
        }
        if(flag)//如果flag为true,说明有空格,则将空格变成了, 
        {
            flag=!flag;
            OutputStr[cnt++]=',';
        }
        OutputStr[cnt++]=pInputStr[i];
    }
    OutputStr[cnt]='\0';
}
二:将一个字符串中出现次数最少的字符删掉,并保证删除后的字符顺序不变,如果出现次数最少的字符有多种,则这几种字符都要删除,该字符串长度不会超过20个字符。 例如:源字符串为“abcdd”,删除后为“dd”
解:此题主要是内存移位操作




char *deleteMin(char *InputSrc,int ILen)
{
    int sz[26]={0};
    int min=20,i;//最小出现次数
    for(i=0;i<ILen;i++)
        ++sz[InputSrc[i]-'a'];
    for(i=0;i<26;i++)
        if(sz[i]<min&&sz[i]!=0)
            min=sz[i];
    for(int t=0;*(InputSrc+t);++t)
        if(sz[InputSrc[t]-'a']==min)
        {
            memcpy(InputSrc+t,InputSrc+t+1,ILen-t);
            --t;//因为跳过了一位
        }
    return InputSrc;
}