牛客--华为机试(3)

题目1

查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。(与上一节题目7相似,利用动态规划)

#include
#include
using namespace std;

int main(){
    string str1, str2;
    while (cin >> str1 ){
        cin >> str2; 
        if (str1.size() > str2.size())
            swap(str1,str2);
        int length1 = str1.size();
        int length2 = str2.size();
        
        int matrix[length1+1][length2+1];
        memset(matrix, 0, sizeof(matrix));
        int max = 0, maxRow = 0;
        
        for (int i = 1; i <= length1; i++){
            for (int j = 1; j <= length2; j++){
                if (str1[i-1] == str2[j-1])
                    matrix[i][j] = matrix[i-1][j-1] + 1;
                if (matrix[i][j] > max){
                    max = matrix[i][j];
                    maxRow = i;
                }
            }
        }
        cout << str1.substr(maxRow-max,max) << endl;
    }
}
题目2

计算整数二进制中1的个数。(使用位运算)

#include 
using namespace std;

int main(){
    int n;
    while(cin >> n){
        int count = 0;
        while (n){
            count++;
            n = n & (n-1);
        }
        cout << count << endl;
    }
}
题目3

完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。
例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。
给定函数count(int n),用于计算n以内(含n)完全数的个数。计算范围, 0 < n <= 500000。返回n以内完全数的个数。 异常情况返回-1

#include
using namespace std;
bool isPrefect(int n){
    int sum = 0;
    for (int i = 1; i < n; i++){
        if (n % i == 0)
            sum += i;
    }
    if (sum == n)
        return true;
    else
        return false;
}

int main(){
    int n;
    while (cin >> n){
        if (n <= 0 || n>= 500000)
            cout << -1 << endl;
        else{
            int count = 0;
            for (int i = 1; i <= n; i++){
                if (isPrefect(i))
                    count++;
            }
            cout << count << endl;
        }
    }
}
题目4

求杨辉三角形的第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3。

#include
#include 
using namespace std;

int main(){
    int n;
    while (cin >> n){
        int m = 2 * n - 1;
        int matrix[n][m];
        memset(matrix,0,sizeof(matrix));
        matrix[0][n-1] = 1;
        
        for (int i = 1; i < n; i++){
            for (int j = 1; j < m; j++){//对第n行,第一个数为1,所以从第二个数考虑的,比较方便
                matrix[i][j] = matrix[i-1][j-1] + matrix[i-1][j] + matrix[i-1][j+1];
            }
        }
        for (int k = 1; k < n; k++){
            if (matrix[n-1][k] % 2 == 0){
                cout << k+1 << endl;
                break;
            }
        }
    }
    return 0;
}
题目5

有一只兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子,假如兔子都不死,问每个月的兔子总数为多少?(讨论一月大、二月大、三月大的兔子有多少只)

#include
using namespace std;

int main(){
    int n;
    while(cin >> n){
        int oneMonth = 1, twoMonth = 0, threeMonth = 0;
        for (int i = 2; i <= n; i++){
            threeMonth += twoMonth;
            twoMonth = oneMonth;
            oneMonth = threeMonth;
        }
        cout << oneMonth + twoMonth + threeMonth << endl;
    }
}
题目6

有这样一道智力题:“某商店规定:三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶,她最多可以换多少瓶汽水喝?”答案是5瓶,方法如下:先用9个空瓶子换3瓶汽水,喝掉3瓶满的,喝完以后4个空瓶子,用3个再换一瓶,喝掉这瓶满的,这时候剩2个空瓶子。然后你让老板先借给你一瓶汽水,喝掉这瓶满的,喝完以后用3个空瓶子换一瓶满的还给老板。如果小张手上有n个空汽水瓶,最多可以换多少瓶汽水喝

#include
using namespace std;
int main(){
    int n;
    while (cin >> n){
        if (n == 0)
            return 0;
        int drinkCount = 0;
        while (n > 2){
            drinkCount += n / 3;//喝的数量
            n = n / 3 + n % 3;//空瓶数量
        }
        if (n == 2)
            drinkCount++;
        cout << drinkCount << endl;
    }
    return 0;
}
题目7

写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)

#include
#include 
using namespace std;

int main(){
    string str;
    while (cin >> str){
        int length = str.size();
        string reversedStr;
        for (int i = 1; i <= length; i++)
            reversedStr.push_back(str[length-i]);
        cout << reversedStr << endl;
    }
}
题目8

输入一个整数,将这个整数以字符串的形式逆序输出。

#include
using namespace std;
int main(){
    int n;
    while(cin >> n){
        while (n != 0){
            cout << n % 10;
            n = n / 10;
        }
        cout << endl;
    }
}
题目9

扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A、2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用"-“连接,每手牌的每张牌以空格分隔,”-"两边没有空格,如:4 4 4 4-joker JOKER。
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR。
基本规则:
(1)输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子);
(3)大小规则跟大家平时了解的常见规则相同,个子、对子、三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;
(4)输入的两手牌不会出现相等的情况。
要点:取左右手牌的第一张牌的时候,不能直接取第一个字符,而是要取第一个空格前的所有字符,如10.为了方便比较牌的大小,将字符转化为数字。

#include
#include 
#include 
using namespace std;

int main(){
    map<string,int> m;
    m["3"] = 3; m["4"] = 4; m["5"] = 5; m["6"] = 6; m["7"] = 7;m["8"] = 8; m["9"] = 9;
    m["10"] = 10; m["J"] = 11; m["Q"] = 12; m["K"] = 13; m["A"] = 14; m["2"] = 15;
    
    string poker;
    while (getline(cin,poker)){
        int pos = poker.find('-');
        string leftPoker = poker.substr(0,pos);
        string rightPoker = poker.substr(pos+1);

        int leftCount = 0, rightCount = 0;//计算两手牌的数量
        for (int i = 0; i < leftPoker.size(); i++){
            if (leftPoker[i] == ' ')
                leftCount++;
        }
        leftCount++;
        for (int i = 0; i < rightPoker.size(); i++){
            if (rightPoker[i] == ' ')
                rightCount++;
        }
        rightCount++;
        
        string leftPokerFirst = leftPoker.substr(0,leftPoker.find(' '));
        string rightPokerFirst = rightPoker.substr(0,rightPoker.find(' '));

        string result;
        if (leftPoker == "joker JOKER" || rightPoker == "joker JOKER"){//一方有王炸
            result = "joker JOKER";
        }
        else if (leftCount == 4 || rightCount == 4){//一方有炸弹
            if (leftCount == 4 && rightCount == 4)
                result = m[leftPokerFirst] < m[rightPokerFirst] ? rightPoker : leftPoker;
            else if (leftCount == 4)
                result = leftPoker;
            else
                result = rightPoker;
        }
        else if (leftCount == rightCount){
            result = m[leftPokerFirst] < m[rightPokerFirst] ? rightPoker : leftPoker;
        }
        else
            result = "ERROR";
        cout << result << endl;
    }
}
题目10**

对于不同的字符串,我们希望能有办法判断相似程度,我们定义了一套操作方法来把两个不相同的字符串变得相同,具体的操作方法如下:
1 修改一个字符,如把“a”替换为“b”。
2 增加一个字符,如把“abdd”变为“aebdd”。
3 删除一个字符,如把“travelling”变为“traveling”。
比如,对于“abcdefg”和“abcdef”两个字符串来说,我们认为可以通过增加和减少一个“g”的方式来达到目的。上面的两种方案,都只需要一次操作。把这个操作所需要的次数定义为两个字符串的距离,而相似度等于“距离+1”的倒数。也就是说,“abcdefg”和“abcdef”的距离为1,相似度为1/2=0.5.
给定任意两个字符串,你是否能写出一个算法来计算出它们的相似度呢?
解题方法:使用动态规划。假设第一个字符串str1长度为M,第二个字符串str2长度为N。
1.求解状态转移矩阵 d p [ M + 1 ] [ N + 1 ] dp[M + 1][N + 1] dp[M+1][N+1], d p [ i ] [ j ] dp[i][j] dp[i][j] 的值代表的是将str1的前i个字符str1[0…i-1]编辑为str2的前j个字符str2[0…j-1]
的最小代价。
2. 计算过程:
1) d p [ 0 ] [ 0 ] = 0 dp[0][0] = 0 dp[0][0]=0,表示str1空的字串编辑为str2空的字串代价为0。
2)矩阵dp第一列即为 d p [ 0... M − 1 ] [ 0 ] dp[0...M-1][0] dp[0...M1][0], d p [ i ] [ 0 ] dp[i][0] dp[i][0]表示str1[0…i-1]编辑为空串的最小代价,所以就是将str1[0…M-1]的字符删掉的代价, 所以dp[i][0] = i;
3) 同2),那str2[0…j-1]编辑的代价,dp[0][j] = j;
4) 接下来的位置就按照从左到右,从上到下来计算,dp[i][j]的值来至于下面的几种情况:
(1) 删除:将 s t r 1 [ 0.. i − 2 str1[0..i-2 str1[0..i2]编辑为 s t r 2 [ 0... j − 1 ] str2[0...j-1] str2[0...j1],然后删除字符 s t r 1 [ i − 1 ] , d p [ i − 1 ] [ j ] str1[i-1], dp[i-1][j] str1[i1],dp[i1][j]表示 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i2]编辑为s t r 2 [ 0... j − 1 ] tr2[0...j-1] tr2[0...j1]的最小代价,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]可能等于 d p [ i − 1 ] [ j ] + 1 dp[i -1][j] + 1 dp[i1][j]+1;

(2)插入:将 s t r 1 [ 0... i − 1 ] str1[0...i-1] str1[0...i1]可以先编辑为 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j2],然后将 s t r 2 [ j − 1 ] str2[j-1] str2[j1]插入到 s t r 1 [ i − 1 ] str1[i-1] str1[i1] s t r 1 [ i ] str1[i] str1[i]之间, d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j1]表示 s t r 1 [ 0.. i − 1 ] str1[0..i-1] str1[0..i1]编辑成 s t r 2 [ 0... j − 2 ] str2[0...j-2] str2[0...j2]的最小代价,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]可能等于 d p [ i ] [ j − 1 ] + 1 dp[i][j-1] + 1 dp[i][j1]+1;

(3) 如果 s t r 1 [ i − 1 ] ! = s t r 2 [ j − 1 ] str1[i - 1]!=str2[j-1] str1[i1]!=str2[j1],那么先把 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i2]编辑成 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j2],然后把字符 s t r 1 [ i − 1 ] str1[i-1] str1[i1]替换为 s t r 2 [ j − 1 ] str2[j-1] str2[j1],这样 s t r 1 [ 0.. i − 1 ] str1[0..i-1] str1[0..i1]就编辑成为 s t r 2 [ 0... j − 1 ] str2[0...j-1] str2[0...j1]了, d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i1][j1]表示 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i2]编辑为 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j2]的最小代价,那么 d p [ i ] [ j ] dp[i ][j] dp[i][j]可能等于 d p [ i − 1 ] [ j − 1 ] + 1 dp[i - 1][j - 1] + 1 dp[i1][j1]+1;

(4) 如果 s t r 1 [ i − 1 ] = = s t r 2 [ j − 1 ] str1[i - 1]==str2[j-1] str1[i1]==str2[j1] ,那么先把 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i2]编辑成 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j2],因为此时 s t r 1 [ i − 1 ] = = s t r 2 [ j − 1 ] str1[i - 1]==str2[j-1] str1[i1]==str2[j1] ,所以 s t r 1 [ 0.. i − 1 ] 已 经 编 辑 为 s t r 2 [ 0.. j − 1 ] str1[0..i-1]已经编辑为str2[0..j-1] str1[0..i1]str2[0..j1]了, d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i1][j1]表示 s t r 1 [ 0.. i − 2 ] str1[0..i-2] str1[0..i2]编辑为 s t r 2 [ 0.. j − 2 ] str2[0..j-2] str2[0..j2]的最小代价, 那么 p [ i ] [ j ] p[i ][j] p[i][j]可能等于 d p [ i − 1 ] [ j − 1 ] dp[i - 1][j - 1] dp[i1][j1]
上述的4中情况取最小值,dp的最右下角就是最终结果,即最小编辑代价。

#include
#include
#include
using namespace std;

int main(){
    string str1, str2;
    while (cin >> str1 >> str2){
        int length1 = str1.size();
        int length2 = str2.size();
        int dpMatrix[length1+1][length2+1];
        memset(dpMatrix,0,sizeof(dpMatrix));
        
        for(int i = 1; i <= length1; i++)
            dpMatrix[i][0] = i;
        for (int j = 1; j <= length2; j++)
            dpMatrix[0][j] = j;
        for (int i = 1; i <= length1; i++){
            for (int j = 1; j <= length2; j++){
                int caseOne = dpMatrix[i-1][j] + 1;
                int caseTwo = dpMatrix[i][j-1] + 1;
                int caseThree = 0;
                if (str1[i-1] == str2[j-1])
                    caseThree = dpMatrix[i-1][j-1];
                else
                    caseThree = dpMatrix[i-1][j-1] + 1;
                dpMatrix[i][j] = min(caseOne,min(caseTwo,caseThree));
            }
        }
        cout << 1 << "/" << (dpMatrix[length1][length2] + 1) << endl;
    }
}

你可能感兴趣的:(笔试练习)