【面试笔试算法】牛客网一站通Offer编程题2016.4.19

时间:2022-05-30 07:50:22

牛客网一站通offer

(一)字符串变形

1. 题目:

对于一个给定的字符串,我们需要在线性(也就是O(n))的时间里对它做一些变形。首先这个字符串中包含着一些空格,就像”Hello

World”一样,然后我们要做的是把着个字符串中由空格隔开的单词反序,同时反转每个字符的大小写。比如”Hello

World”变形后就变成了”wORLD hELLO”。

输入描述:

给定一个字符串s以及它的长度n(1≤n≤500)

输出描述:

请返回变形后的字符串。题目保证给定的字符串均由大小写字母和空格构成。

输入例子:

“This is a sample”,16

输出例子:

“SAMPLE A IS tHIS”

2. 解题

这道题看上去不是很难,可是很多边界问题 需要考虑。

比如:##this#is#a#sample## 返回 ##SAMPLE#A#IS#THIS##,而不是SAMPLE#A#IS#THIS。(Tips:#代表空格)

本题的思路:首先将字符串大小写进行替换,然后反转整个字符串,最后反转每个单词,其他的不改变。

Accepted代码:

    class Transform {
    public:
        string trans(string s, int n) {
            // write code here
            //大小写替换
            for(int i = 0 ; i < n ;i++){
                if(s[i]>='a'&&s[i]<='z'){
                    s[i] = toupper(s[i]);
                }
                else if(s[i]>='A'&&s[i]<='z'){
                    s[i] = tolower(s[i]);
                }
            }
            //反转整个字符串
            reverse(s.begin(),s.end());
            auto pbegin = s.begin();
            auto pend = s.begin();
            while(*pend!='\0'){
                if(*pend == ' '){
                    //碰到空格则反转单词
                    reverse(pbegin,pend);
                    pbegin = pend+1;
                }
                ++pend;
            }
            //处理边界情况,字符串末尾的单词需要反转
            reverse(pbegin,pend);
            return s;
        }
    };

(二)地域划分

1.题目

现在有一块长条形的土地,这个土地我们可以看成是由n块小方格连接而成的(这些小方格我们可以将之编号为1到n)。而我们需要将其划分成两个部分,分别种上不同的作物(即作物A和B),划分必须在某两个小方格之间进行,或者在土地的最左端或最右端,若划分在第i块到第i+1块间进行,则划分后,第1至第i块地种A,剩下的地种B。现在有一些专家对土地进行了检测,他们每个人评估了每块土地适合种的作物。请你找到一个合适的划分,使得其与所有专家的评估最吻合,也就是说,你划分到A而专家评估为B的次数和你划分到B而专家评估为A的次数之和最小。

输入描述:

每组数据给定一个专家评估表land(其中0为评估A,1为评估B),以及小块数量n(1≤n≤300),专家评估次数m(1≤m≤300)

输出描述:

请返回你的划分,即i和i+1。若在最左端,则输出0,1;在最右端则输出n,n+1。若有多解输出最靠左的划分。

输入例子:

[[1,1,1,1],[0,0,0,0],[1,0,1,1]],4,3

输出例子:

[0,1]

2. 解题

按照自己的划分(有n+1种划分),依次逐位和专家的划分进行对比,求出最小值。

例如:

我的划分 专家划分1 专家划分2 专家划分3 结果
1111 1111 0000 1011 5
0111 1111 0000 1011 6
0011 1111 0000 1011 5
0001 1111 0000 1011 6
0000 1111 0000 1011 7

故输出为[0,1]

Accpeted代码:

class Partition {
public:
        vector<int> getPartition(const vector<vector<int> >& land, int n, int m) {
            // write code here
            int min = 10000000;
            int idx = -1;
            for(int i = -1 ; i < n ; i++){
                int count = 0;
                for(int j = 0 ;j < m ; j++){
                    int ps = i;//我的划分
                    int pe = i+1;
                    while(ps>=0) {//左边区域对比
                        if(land[j][ps] == 1){
                            count++;
                        }
                        ps--;
                    }
                    while(pe<n) {//右边区域对比
                        if(land[j][pe] == 0){
                            count++;
                        }
                        pe++;
                    }
                }
                if(count<min){//保存最小值
                    min = count;
                    idx = i;
                }
            }
            vector<int> ret;
            ret.push_back(idx+1);
            ret.push_back(idx+2);
            return ret;
        }
    };

(3) 树上最长单色路径

1. 题目

对于一棵由黑白点组成的二叉树,我们需要找到其中最长的单色简单路径,其中简单路径的定义是从树上的某点开始沿树边走不重复的点到树上的另一点结束而形成的路径,而路径的长度就是经过的点的数量(包括起点和终点)。而这里我们所说的单色路径自然就是只经过一种颜色的点的路径。你需要找到这棵树上最长的单色路径。

给定一棵二叉树的根节点(树的点数小于等于300,请做到O(n)的复杂度),请返回最长单色路径的长度。这里的节点颜色由点上的权值表示,权值为1的是黑点,为0的是白点。

2. 解题

这题用动态规划来求解。需要用到一对引用传值(white和black)来记录每个节点的左右孩子节点的黑白路径长度值传递上来。

如:lhswhite ,lhsblack ,rhswhite,rhsblack分别表示两个孩子节点的黑白最长路径长度

分两类情况:

(1)当父节点为黑时:其white = 0,black = max(lhsblack+1,rhsblack+1),它的最长单色路径长度为lhsblack+rhsblack+1;

(2)当父节点为白时:其black = 0,white = max(lhswhite+1,rhswhite+1),它的最长单色路径长度为lhswhite+rhswhite+1;

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/

class LongestPath {
public:
    int ret=0;
    int findPath(TreeNode* root) {
        // write code here
        int white = 0,black =0;
        dfsPath(root , white , black);
        return ret;
    }
    void dfsPath(TreeNode* root , int &white , int &black){
        if(root->left == NULL && root->right == NULL){
            if(root->val == 1){
                white = 0;black = 1;
            }
            else{
                white = 1;black = 0;
            }
        }
        else{
            int lhswhite = 0,lhsblack =0;
            int rhswhite = 0,rhsblack =0;
            if(root->left != NULL) dfsPath(root->left,lhswhite,lhsblack);
            if(root->right !=NULL) dfsPath(root->right,rhswhite,rhsblack);
            if(root->val ==1){
                if(lhsblack+rhsblack+1>ret) ret = lhsblack+rhsblack+1;
                white = 0;
                black = lhsblack+1>rhsblack+1?lhsblack+1:rhsblack+1;
            }
            else{
                if(lhswhite+rhswhite+1>ret) ret = lhswhite+rhswhite+1;
                black = 0;
                white = lhswhite+1>rhswhite+1?lhswhite+1:rhswhite+1;
            }
        }
    }
};

(四)串珠子

1. 题目

现在A和B在玩一个游戏,这个游戏首先给了他们很多珠子,珠子有两种颜色,一种蓝色,一种黄色,我们假定两种珠子都有无限多。A需要选择n颗珠子(n为奇数),然后由B串成一串项链(顺序由B确定,这里的项链也就是一个环)。假如在最后串成的项链中,A能够找到两个不同位置的蓝色珠子,并在这两处把这个项链断开成两段,其中一段恰好长度为(n+1)/2那么A就胜利了,注意这里为整数截断除法且这个长度是不包括选出的两颗珠子的。现在请你计算出A至少要选择多少颗蓝色珠子,才能保证无论B怎么串,他都能获胜。举个例子,当A选了7颗珠子,其中有3颗蓝珠子,那么如果B串的项链为”蓝蓝红红红红蓝”,则A能获胜,若B串的项链为”蓝蓝红红蓝红红”,则A不能获胜。

2. 解题

这是一题找规律的题目。

class Chain {
public:
    int findK(int n) {
        // write code here
        if(n%3==0) return n/2;
        else return (n+1)/2;
    }
};