google的几道面试题

Question1:如何判断两个矩形是否有重叠区域?

Answer(java):

public boolean checkCross(Rectangle m, Rectangle n)

{

   //求出m,n矩形的重心

  Point m_core = new Point(m.getLeft().getX() + m.getLength()/ 2, m.getLeft().getY() + m.getWidth()/ 2);

  Point n_core = new Point(n.getLeft().getX() + n.getLength()/ 2, n.getLeft().getY() + n.getWidth()/ 2);

  return Math.abs(m_core.getX() - n_core.getX()) < (m.getLength()/ 2 + n.getLength()/ 2) &&

  Math.abs(m_core.getY()-n_core.getY()) < (m.getLength()/ 2 + n.getWidth()/ 2);

}

原理如下图所示:

clip_image002

 

Question2: 给出一个函数,对一个数组进行随机排列,每种排列出现的概率是n!分之一

Answer(java):

public int[] rank(int[] m ,int length){

    public int[] rank(int[] m ,int length){

    int[] n=m.clone();

    int place;//表示将放于i位置的数的位置

    int temp;

    for(int i=0;i<length-1;i++){

    //产生【i,length-1】的随机数

    place=i+(int)(Math.random()*(length-i));

    temp=n[place];

    n[place]=n[i];

    n[i]=temp;

    }

    return n;

}

 

Question3:( 约瑟夫环问题)n个人(编号为0~n-1),从0开始报数,报到(m-1)的人退出,剩下的人继续从0开始报数。求最后留下的人的编号。

Answer(java):

1、用循环链表来模拟整个过程

2、令f[n]表示n个人时最后留下的人的编号
     递推公式如下:
     n=1时,f[1]=0;
     n>1时,f[n]=(f[n-1]+m)%n

原理如下图所示:

clip_image004

 

Question4:(1)给一个字符串,要你统计里面的ASCII码的频数,其中大写的字母算作小写字母来统计,输出的时候这样输出:假如字符串是bbCca*  ,则输出b2 C2 a1 *1,按字母首次出现的顺序输出。给出一个c函数的形式为void calcchar* inputint len),你也可以用你喜欢的语言去写。(2)给出测试数据来证明程序运行的各种可能性。

Answer(java):

public void calc(String input,int length){
        //出现的次数统计数组
        int[] ascii_times=new int[128];
        for(int i=0;i<ascii_times.length;i++){
            ascii_times[i]=0;
        }
        
        int lowercase_start=(int)'a';
        int lowercase_end=(int)'z';
        int gap=(int)'a'-(int)'A';
        
        //是否与之前的字符发生重复数组
        boolean[] flag=new boolean[length];
        for(int i=0;i<length;i++){
            flag[i]=false;
        }
        
        //对input数组进行扫描
        for(int i=0;i<length;i++){
            
            int ascii=(int)input.charAt(i);
            if(ascii>=lowercase_start && ascii<=lowercase_end){
                ascii-=gap;
            }
            if(ascii_times[ascii]>0){
                flag[i]=true;
            }
            ascii_times[ascii]++;
        }
        //输出
        for(int i=0;i<length;i++){
            
            int ascii=(int)input.charAt(i);
            if(ascii>=lowercase_start && ascii<=lowercase_end){
                ascii-=gap;
            }
            if(flag[i]==false){
                System.out.println(input.charAt(i)+":"+ascii_times[ascii]+" ");
            }
        }
}

 

Question5:给定一个数组A,里面只出现0-910个数字,但不一定全部出现,然后给定一个K的值,求利用A中数字(不一定全用)构成大于K的最小整数。例如A={01} k =12,则结果为100

Answer(java)

public  int getMinAns(int K,String nums){
        
        int temp_K=K;
        //获取K的位数到K_digits
        int K_digits=0;
        do{
            temp_K=temp_K/10;
            K_digits++;
        }while(temp_K>0);//此处只能用do-while,因为K可能为0
        
        //将K的每一位存到K_nums数组中
        temp_K=K;
        int[] K_nums=new int[K_digits];
        for(int i=K_digits-1;i>=0;i--){
            K_nums[i]=temp_K%10;
            temp_K=temp_K/10;
        }
        
        //初始化K_Answer数组,用于存储试填入其中的数,-1表示不存在
        int[] K_Answer=new int[K_digits+1];
        for(int i=0;i<K_digits;i++){
            K_Answer[i]=K_nums[i];
        }
        K_Answer[K_digits]=-1;
        
        //将nums中出现的数字存到标记数组existNums中表示其存在
        boolean[] existNums=new boolean[10];
        for(int i=0;i<10;i++){
            existNums[i]=false;
        }
        for(int i=0;i<nums.length();i++){
            char a=nums.charAt(i);
            if(a>='0'&& a<='9'){
                existNums[a-'0']=true;
            }
        }
        
        //扫描K_nums,K_nums[p]表示当前扫描到的数字
        int p=0;
        while(p<K_digits){
            
            boolean isrollback=false;
            int findResult=-1;
            findResult=findBigOrEqual(K_Answer[p],existNums);
            
            
            K_Answer[p]=findResult;
            
            if(findResult>K_nums[p]){
                //如果查找的结果大于K中的值,则直接生成后续数字
                    int exist_min=-1;
                    for(int i=0;i<10;i++){
                        if(existNums[i]){
                            exist_min=i;
                            break;
                        }
                    }
                    
                    for(int i=p+1;i<K_digits;i++){
                        K_Answer[i]=exist_min;
                    }
                
                break;//跳出扫描
                
            }
            if(findResult==K_nums[p]){
                //如果查找的结果等于K中值
                
                //如果全部相等
                if(p==K_digits-1){
                    
                        findResult=findBigOrEqual(findResult+1,existNums);
                        if(findResult!=-1){
                            K_Answer[p]=findResult;
                            break;
                        }else{
                            isrollback=true;
                        }
                        
                }else{
                    
                    p++;
                }
                
            }
            if(findResult==-1){
                //如果查找结果为-1
                isrollback=true;
            }
        
            if(isrollback){
                //如果查找的结果小于K中值,回退到上一位
                p--;
                if(p==-1){
                    //直接生成K_digits+1位的最小数
                    boolean exist_zero=false;
                    int nonZeroMin=-1;
                    
                    for(int i=0;i<10;i++){
                        if(existNums[i]){
                            if(i==0){
                                exist_zero=true;
                            }else{
                                nonZeroMin=i;
                                break;
                            }
                            
                        }
                    }
                    //整个existNums中不存在非零数
                    if(nonZeroMin==-1){
                        return -1;
                    }
                    K_Answer[0]=nonZeroMin;
                    for(int i=1;i<K_digits+1;i++){
                        if(exist_zero){
                            K_Answer[i]=0;
                        }
                        else{
                            K_Answer[i]=nonZeroMin;
                        }
                    }
                    
                    break;//退出扫描
                }
                
                K_Answer[p]++;
                
            }
            
        }
        
        //构造int型结果
        int result=0;
        for(int i=0;i<K_digits+1;i++){
            if(K_Answer[i]==-1)
                break;
            result=result*10+K_Answer[i];
            
        }
        
        return result;
        
    }
    
    //查找>=p的最小数,查不到返回-1
    private int findBigOrEqual(int p,boolean[] existNums){
        for(int j=p;j<10;j++){
            if(existNums[j]){
                return j;
            }
        }
        return -1;
    }

  

Question6:19本书,编号从1-19。从中抽五本,任意相邻两本不是相邻编号的情况有多少种。

Answer:

解法一:假设从19本书中拿出5本,结果剩下14本书,这14本书一共有14+1个间隔空位,在这些空位中选出5个,将5本书放回,则5本书均不会相邻。(本题是一个数学问题),

解法二:

 

/*
     * 表示从n本书中抽取m本书,m本书的位置不相邻
     */
public  int extractBooks(int n, int m){
        if( m>0 && n>=2*m-1 ){
            
            //剪枝
            if(n==2*m-1){
                return 1;
            }
            
            if(m==1){
                return n;
            }
            
            int result=0;        
            for(int i=n-2;i>=2*m-3;i--){
                result+=testScript4(i,m-1);
            }
            return result;
        }
        
        return 0;

}

 

 Probleam7;玩过KOF(拳皇)的人都知道,玩的时候会连招是比较强的。题目的大概意思是:每招用一个大写字母表示,如ABC...Z,现给定n个连招公式:S→T,其中S长度为mT的长度为1。在前m招的时候可以随便连,但m+1招后就必须遵循连招公式。现在要写一个算法,计算最长连招的长度;如果可以无限连招,则返回def1≤n,m≤100
给了一个例子:n=4m=3,连招公式为:ABC→CABC→DCCA→ABCC→A(最后一个连招公式忘了,记在纸上落在住处了,晚上改改,不过应该不影响理解)。连招公式的意思是:ABC可以连出C,也可连出DCCA可以连出ABCA、可以连出B。这时候可以得到最长连招公式:ABC→C→A→A,即最长连招公式长度为6

题目要求给出算法思想并结合一定的伪码。

Answer(java):

//初始时start=””
private String kofMax(String start,List<String> movelist,int typelen){
        
        //初始化最大长度maxlen和最大结果max
        int maxlen=start.length();
        String max=start;
        
        for(String nextmove:movelist){
            if(start.length()==0|| nextmove.startsWith(start.substring(start.length()-typelen))
                    ){
                //如果找到下一招
                //如果下一招已经在当前出招链中出现过,则出现循环
                if(start.indexOf(nextmove.substring(nextmove.length()-typelen))!=-1){
                    return start+"eof";
                }
                
                String str=null;
                if(start.length()==0){
                    str=nextmove;
                }else{
                    str=start.substring(0,start.length()-typelen)+nextmove;
                }
                //递归
                String temp=kofMax(str,movelist,typelen);
                
                //如果出现循环
                if(temp.endsWith("eof")){
                    return temp;
                }
                //进行比较
                if(temp.length()>maxlen){
                    maxlen=temp.length();
                    max=temp;
                }
                
            }
        }
        
        return max;
        
    }

 

Question8:给定两个大小分别为nm的整数集合,分别存放在两个数组中int A[n],B[m],输出两个集合的交集

Answer(java):

private int[] interSection(int[] array1,int[] array2){
        //1.对array1和array2进行快排
        quicksort(array1,0,array1.length-1);
        quicksort(array2,0,array2.length-1);
        
        //2.扫描求交集
        Int len=array1.length<array2.length?array1.length:array2.length;
        int[] temp=new int[len];
        for(int i=0;i<len;i++){
            temp[i]=-1;
        }
        
        int i=0,j=0,p=0;
        while(i<array1.length && j<array2.length){
            
            if(array1[i]<array2[j]){
                i++;
            }else if(array1[i]>array2[j]){
                j++;
            }else{
                temp[p]=array1[i];
                p++;
                i++;
                j++;
            }
            
        }
        //返回结果集合
        int[] result=new int[p];
        for(int k=0;k<p;k++){
            result[k]=temp[k];
        }
        return result;
    }

 

Qustion9:对数值范围为0n^2-1n个整数进行排序,请详细描述算法(若引用经典算法也需要给出具体实现),并分析算法的时间复杂度和空间复杂度。要求时间复杂度尽量优化,在此前提下空间复杂度尽量优化。

Answer(java):

由于给定的数值范围特殊,考虑到如果将n个数以n为基进行转化则最多两位,然后进行基排序,其时间复杂度为O(n),相当高效。其基排序实现如下:

private void radixsort(long[] peng,int n){
        Node[] start=new Node[n];//start是对象数组
        Node[] end=new Node[n];//end是引用数组
        
        for(int i=0;i<n;i++){
            start[i]=new Node(0,null);
            end[i]=start[i];
        }
        
        //扫描所有的数,将其转化为链表,头为head
        Node pre=new Node(peng[0],null);
        Node head=pre;
        for(int i=1;i<peng.length;i++){
            Node node=new Node(peng[i],null);
            pre.next=node;
            pre=node;
        }
        //进行若干次分配和收集,智能处理数的位数
        boolean isOver=true;
        for(int i=0;;i++){    
            
            Node p=head;
            //分配
            while(p!=null){
                long b=p.data;
                for(int j=0;j<i;j++){
                    b=b/n;
                }
                int c=(int)b%n;    
                if(c!=0){
                    isOver=false;
                }
                end[c].next=p;
                end[c]=p;
                p=p.next;
            }
            if(isOver){
                break;
            }
            isOver=true;
            
            end[n-1].next=null;//此句目的是将最后的节点的next置空
            
            //链接
            for(int j=n-1;j>0;j--){
                end[j-1].next=start[j].next;
                start[j].next=null;
                end[j]=start[j];
            }
            
            head=start[0].next;
            start[0].next=null;
            end[0]=start[0];
        }
        //返回结果
        Node p=head;
        int i=0;
        while(p!=null){
            peng[i]=p.data;
            i++;
            p=p.next;
        }
    }
    private class Node{
        public long data;
        public Node next;
        public Node(long data, Node next) {
            this.data = data;
            this.next = next;
        }
        
    }

 

Question10:假设银行有4个柜台,假设某天有200位顾客来办理业务,每个顾客到达银行的时间和业务处理时间分别用两个数组arrive_timeprocess_time来描述。

请写程序计算所有客户的平均等待时间,假设每个客户在去到营业部之后先拿号排队,然后在任意一个柜台有空闲的时候,号码数最小的客户上去办理,假设所有客户拿到号码之后不会因为银行众所周知的慢而失去耐心走掉。

Answer(java:

private void bankdeal(Node[] clients){
        int currentTime=0;
        final int counterNum=4;
        //isfree和counterEndTime记录对应的柜台是否有空以及其结束业务时间
        boolean[] isfree=new boolean[counterNum];
        for(int i=0;i<isfree.length;i++){
            isfree[i]=true;
        }
        
        int[] counterEndTime=new int[counterNum];
        for(int i=0;i<counterEndTime.length;i++){
            counterEndTime[i]=currentTime;
        }
        //有没有方式对数组一次赋全值
        
        //扫描每一个client
        int i=0;
        while(i<clients.length){
            //检查那个counter可以用
            for(int j=0;j<counterNum;j++){
                if(isfree[j]){
                    currentTime=currentTime<clients[i].arriveTime?clients[i].arriveTime:currentTime;
                    int endtime=currentTime+clients[i].dealTime;
                    counterEndTime[j]=endtime;
                    clients[i].endTime=endtime;
                    isfree[j]=false;
                    i++;
                }
            }
            //求出counters结束业务最早的那个
            int minCounterEndTime=counterEndTime[0];
            int minflag=0;
            for(int k=0;k<counterNum;k++){
                if(counterEndTime[k]<minCounterEndTime){
                    minCounterEndTime=counterEndTime[k];
                    minflag=k;
                }
            }
            isfree[minflag]=true;
            currentTime=minCounterEndTime;
        }
        
    }
    
 

   //顾客节点
    private class Node{
        int arriveTime;
        int dealTime;
        int endTime;
    }

posted on 2014-09-19 22:53  小杰鱼  阅读(558)  评论(0编辑  收藏  举报

导航