zoukankan      html  css  js  c++  java
  • 2012Google校园招聘笔试题

    1、已知两个数字为1~30之间的数字,甲知道两数之和,乙知道两数之积,甲问乙:“你知道是哪两个数吗?”乙说:“不知道”。乙问甲:“你知道是哪两个数吗?”甲说:“也不知道”。于是,乙说:“那我知道了”,随后甲也说:“那我也知道了”,这两个数是什么?

    答案: 
    允许两数重复的情况下 
    答案为x=1, y=4; 甲知道和A=x+y=5, 乙知道积B=x*y=4 
    不允许两数重复的情况下有两种答案 
    答案1: 为x=1, y=6; 甲知道和A=x+y=7, 乙知道积B=x*y=6 
    答案2: 为x=1, y=8; 甲知道和A=x+y=9, 乙知道积B=x*y=8 
    
    解: 
    设这两个数为x,y. 
    甲知道两数之和 A=x+y; 
    乙知道两数之积 B=x*y; 
    
    该题分两种情况 
    允许重复, 有(1 <= x <= y <= 30); 
    不允许重复,有(1 <= x < y <= 30); 
    
    当不允许重复, 即(1 <= x < y <= 30); 
    
    1)由题设条件:乙不知道答案 
    <=> B=x*y 解不唯一 
    => B=x*y 为非质数 
    
    又∵ x ≠ y 
    ∴ B ≠ k*k (其中k∈N) 
    
    结论(推论1): 
    B=x*y 非质数且 B ≠ k*k (其中k∈N) 
    即:B ∈(6,8,10,12,14,15,18,20...) 
    证明过程略 
    
    2)由题设条件:甲不知道答案 
    <=> A=x+y 解不唯一 
    => A >= 5; 
    
    分两种情况 
    A=5,A=6时x,y有双解 
    A>=7 时x,y有三重及三重以上解 
    
    假设 A=x+y=5 
    则有双解 
    x1=1,y1=4; 
    x2=2,y2=3 
    代入公式B=x*y: 
    B1=x1*y1=1*4=4; (不满足推论1,舍去) 
    B2=x2*y2=2*3=6; 
    得到唯一解x=2,y=3 即甲知道答案 
    与题设条件:“甲不知道答案”相矛盾 
    故假设不成立, A=x+y≠5 
    
    假设 A=x+y=6 
    则有双解 
    x1=1,y1=5; 
    x2=2,y2=4 
    代入公式B=x*y: 
    B1=x1*y1=1*5=5; (不满足推论1,舍去) 
    B2=x2*y2=2*4=8; 
    得到唯一解x=2,y=4 
    即甲知道答案 
    与题设条件:“甲不知道答案”相矛盾 
    故假设不成立, A=x+y≠6 
    
    当A>=7时 
    ∵ x,y的解至少存在两种满足推论1的解 
    B1=x1*y1=2*(A-2) 
    B2=x2*y2=3*(A-3) 
    ∴ 符合条件 
    
    结论(推论2):A >= 7 
    
    3)由题设条件:乙说“那我知道了” 
    => 乙通过已知条件B=x*y及推论(1)(2)可以得出唯一解 
    即: 
    
    A=x+y, A >= 7 
    B=x*y, B ∈(6,8,10,12,14,15,16,18,20...) 
    1 <= x < y <= 30 
    x,y存在唯一解 
    
    当 B=6 时:有两组解 
    x1=1, y1=6 
    x2=2, y2=3 (∵ x2+y2=2+3=5 < 7 ∴不合题意,舍去) 
    得到唯一解 x=1, y=6 
    
    当 B=8 时:有两组解 
    x1=1, y1=8 
    x2=2, y2=4 (∵ x2+y2=2+4=6 < 7 ∴不合题意,舍去) 
    得到唯一解 x=1, y=8 
    
    当 B>8 时:容易证明均为多重解 
    
    结论: 
    当B=6时有唯一解 x=1, y=6 当B=8时有唯一解 x=1, y=8 
    
    4)由题设条件:甲说“那我也知道了” 
    => 甲通过已知条件A=x+y及推论(3)可以得出唯一解 
    
    综上所述,原题所求有两组解: 
    x1=1, y1=6 
    x2=1, y2=8 
    
    当x<=y时,有(1 <= x <= y <= 30); 
    同理可得唯一解 x=1, y=4

    2、一个环形公路,上面有N个站点,A1, ..., AN,其中Ai和Ai+1之间的距离为Di,AN和A1之间的距离为D0。
    高效的求第i和第j个站点之间的距离,空间复杂度不超过O(N)
    它给出了部分代码如下:

    #define N 25
    double D[N] 
    ....
    void Preprocess()
    {
         //Write your code1;
    }
    double Distance(int i, int j)
    {
          //Write your code2;
    }
    const int N = 10;  
    int D[N];  
      
    int A1toX[N];  
      
    void Preprocess()  
    {  
        srand(time(0));  
      
        for (int i = 0; i < N; ++i)  
        {  
            D[i] = (rand()/(RAND_MAX+1.0)) * N;  
        }  
      
        A1toX[1] = D[1];     //from A1 to A2  
        for (int i = 2; i < N; ++i)  
        {  
            A1toX[i] = A1toX[i-1] + D[i];    //distance from A1 to each point  
        }  
        A1toX[0] = A1toX[N-1] + D[0];    // total length  
    }  
      
    int distance(int i, int j)  
    {  
        int di = (i == 0) ? 0 : A1toX[i-1];  
        int dj = (j ==0) ? 0 : A1toX[j-1];  
        int dist = abs(di - dj);  
        return dist > A1toX[0]/2 ? A1toX[0] - dist : dist;  
    }  
      
    int main(void)  
    {  
        Preprocess();  
        for (int i = 0; i <N; ++i)  
        {  
            cout<<D[i]<<" ";  
        }  
        cout<<endl;  
        for (int i = 1; i <= N; ++i)  
        {  
            cout<<"distance from A1 to A"<<i<<": "<<distance(1, i)<<endl;  
        }  
        return 0;  
    }  

    3、 一个字符串,压缩其中的连续空格为1个后,对其中的每个字串逆序打印出来。比如"abc   efg  hij"打印为"cba gfe jih"。

    #include<iostream>  
    #include<cstdio>  
    #include<stack>  
    #include<string>  
    using namespace std;  
      
    string reverse(string str)  
    {  
        stack<char> stk;  
        int len = str.length();  
        string ret = "";  
      
        for (int p = 0, q = 0;p < len;)  
        {  
            if (str[p] == ' ')  
            {  
                ret.append(1,' ');  
                for (q = p; q < len && str[q] == ' '; q++)  
                {}  
                p = q;  
            }  
            else  
            {  
                for (q = p; q < len && str[q] != ' '; q++)  
                {  
                    stk.push(str[q]);  
                }  
                while(!stk.empty())  
                {  
                    ret.append(1,stk.top());  
                    stk.pop();  
                }  
                p = q;  
            }  
        }  
        return ret;  
    }  
    int main(void)  
    {  
        string s = "abc def   ghi";  
        cout<<reverse(s).c_str()<<endl;  
        return 0;  
    }   

    4、将一个较大的钱,不超过1000000(10^6)的人民币,兑换成数量不限的100、50、10、5、2、1的组合,请问共有多少种组合呢?(完全背包)(其它选择题考的是有关:操作系统、树、概率题、最大生成树有关的题。)。

    第一种方法(母函数):

    #define NUM 7  
    int money[NUM] = {1, 2, 5, 10, 20, 50, 100};  
      
    // 母函数解法  
    int NumOfCoins(int value)  
    {  
        int i , j , k , c1[1010] , c2[1010];  
        for(i = 0 ; i <= value ; ++i)  
        {  
            c1[i] = 1;  
            c2[i] = 0;  
        }  
        //第一层循环是一共有 n 个小括号,而刚才已经算过一个了     
        // i 就是代表的母函数中第几个大括号中的表达式   
        for(i = 1 ; i < NUM ; ++i)  
        {  
            for(j = 0 ; j <= value ; ++j)   //j 就是指的已经计算出的各项的系数  
            {  
                for(k = 0 ; k+j <= value ; k += money[i])  //k 就是指将要计算的那个括号中的项  
                    c2[k+j] += c1[j];  
            }  
            for(j = 0 ; j <= value ; ++j)  // 刷新一下数据,继续下一次计算,就是下一个括号里面的每一项  
            {  
                c1[j] = c2[j];  
                c2[j] = 0;  
            }  
        }  
        return c1[value];  
    }  

    第二种方法(动态规划):
    我们可以将它形式化为:

     

    硬搜的话肯定是可以出结果的,但时间复杂度太高。
    第一种方法:
    设 F[n] 为用那么多种面值组成 n 的方法个数。则 F[n] 可以分成这样互不重复的几个部分:
    只用 50 及以下的面值构成 [n] + 0 张 100
    只用 50 及以下的面值构成 [n-100] + 1 张 100
    只用 50 及以下的面值构成 [n-200] + 2 张 100
    ……
    也就是说,按 F[n] 的组成方案中 100 的张数,将 F[n] 划分成若干等价类,等价类的划分要不重复、不遗漏。这些等价类恰好完整覆盖了 F[n] 的所有情况。
    然后对于 50 及以下的方案又可以按 50 的张数划分等价类。于是像这样一层一层递归下去……就可以得到结果了。
    把上面的递归过程反过来,从下往上递推,这就是动态规划了。代码(用到了一些 C99 特性,比如栈上的可变长数组):
    时间复杂度 < O(N^2)

    #define NUM 7  
    int money[NUM] = {1, 2, 5, 10, 20, 50, 100};  
    // 动态规划解法  
    int NumOfCoins(int value)  
    {  
        int i , j , t , dp[7][1010];  
        for(i = 0 ; i <= value ; ++i)  
            dp[0][i] = 1;  
      
        for(i = 1 ; i < NUM ; ++i)  
        {  
            for(j = 0 ; j <= value ; ++j)  
            {  
                t = j;  
                dp[i][j] = 0;  
                while(t >= 0)  
                {  
                    dp[i][j] += dp[i-1][t];  
                    t -= money[i];  
                }  
            }  
        }  
        return dp[6][value];  
    }  

    其中 dp[i][j] 表示只用第 i 张面值及以下构成 j 用多少种方法。
    改进如下:
    a[6][n] = ar[6][n-100]     // 至少包含 1 张 100 的拆分个数
                  + ar[5][n]         // 不包含 100 的拆分个数

    直接把时间复杂度从 O(n^2) 降到了 O(n):

    #define NUM 7  
    int money[NUM] = {1, 2, 5, 10, 20, 50, 100};  
    // 动态规划解法(完全背包)  
    int NumOfCoins(int value)  
    {  
        int i , j , dp[7][1010];  
        for(i = 0 ; i <= value ; ++i)  
            dp[0][i] = 1;  
      
        for(i = 1 ; i < NUM ; ++i)  
        {  
            for(j = 0 ; j <= value ; ++j)  
            {  
                if(j >= money[i])  
                    dp[i][j] = dp[i][j - money[i]] + dp[i - 1][j];  
                else  
                    dp[i][j] = dp[i-1][j];  
            }  
        }  
        return dp[6][value];  
    }  

    或者使用滚动数组也是可以的

    #define NUM 7    
    int money[NUM] = {1, 2, 5, 10, 20, 50, 100};   
    int f[1010] , bf[1010];  
    // f[j] == f[i][j]   bf[j] == bf[i-1][j]  
    int NumofCoin2(int value)  
    {  
        int i , j;  
        for(j = 0 ; j <= value ; ++j)  
            f[j] = 0 , bf[j] = 0;  
        bf[0] = 1;  
      
        for(i = 0 ; i < NUM ; ++i)  
        {  
            for(j = 0 ; j <= value ; ++j)  
            {  
                if(j >= money[i])  
                    f[j] = f[j-money[i]] + bf[j];  
                else  
                    f[j] = bf[j] ;  
            }  
      
            for(j = 0; j <= value ; ++j)  
                bf[j] = f[j] , f[j] = 0;  
        }  
        return bf[value];  
      
    }  

     

  • 相关阅读:
    python操作adb代码
    android sdcard 权限管理策略研究
    glom模块的使用(二)
    爬虫错误汇总
    微博展开全文获取
    数据清洗之微博内容清洗
    Esxi5-管理平台vcenter5.0_数据库迁移流程
    migrating-vcenter-database-express-to-sql-2008-r2
    Centos生成SSL证书的步骤
    找到一篇关于2.4/5G信道的新介绍
  • 原文地址:https://www.cnblogs.com/sooner/p/3283692.html
Copyright © 2011-2022 走看看