【From牛客网】各厂笔试训练题目

来源:互联网 发布:tik江苏泰微课网络课程 编辑:程序博客网 时间:2024/05/21 09:25

声明:题目来源是牛客网,本人不对题目真实性负责,仅供参考、分享。

A. 递归生成格雷码(鹅厂)

在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同, 则称这种编码为格雷码(Gray Code),请编写一个函数,使用递归的方法生成N位的格雷码。
给定一个整数n,请返回n位的格雷码,顺序为从0开始。

测试样例: 1
返回:[“0”,”1”]

我的实现:

class GrayCode {public:    vector<string> getGray(int n) {        int size = (1 << n);        vector<string> v(size);        if (n == 1) {            v[0] = "0";            v[1] = "1";            return v;        }        vector<string> suffix = getGray(n-1);        for (int i = 0; i < suffix.size(); ++i) {            v[i] = "0" + suffix[i];            v[size-i-1] = "1" + suffix[i];        }        return v;    }};

n位的格雷码是一个n位字符串的序列,比如[“00”, “01”, “11”, “10”]就是2位格雷码了,它的特点是——序列中相邻两个码只相差一个二进制位,这是怎么实现的呢???按我的看法的话,格雷码其实就是一棵完整的二叉树,如下图:
格雷码生成过程
对于同样的后缀,比如0,在生成的序列中[“00”, “01”, “11”, “10”],分别用0和1放在”0”的前面组成了”00”和”10”,它们的位置是“中心对称”的,可能看下面的图会比较明显一点:
这里写图片描述
所以递归就上面那样写了,同时考虑一些迭代是否也可以写?答案是肯定的,就是模拟上面的递归过程,参考:
http://www.cnblogs.com/0201zcr/p/4796950.html

B. 比较重量(猪厂)

小明陪小红去看钻石,他们从一堆钻石中随机抽取两颗并比较她们的重量。这些钻石的重量各不相同。在他们们比较了一段时间后,它们看中了两颗钻石g1和g2。现在请你根据之前比较的信息判断这两颗钻石的哪颗更重。
给定两颗钻石的编号g1,g2,编号从1开始,同时给定关系数组vector,其中元素为一些二元组,第一个元素为一次比较中较重的钻石的编号,第二个元素为较轻的钻石的编号。最后给定之前的比较次数n。请返回这两颗钻石的关系,若g1更重返回1,g2更重返回-1,无法判断返回0。输入数据保证合法,不会有矛盾情况出现。

测试样例: 2,3,[[1,2],[2,4],[1,3],[4,3]],4
返回: 1

class Cmp {public:    int cmp(int g1, int g2, vector<vector<int> > records, int n) {        // 由于输入没给size,所以需要自己求解        int maxN = -1;        for (int i = 0; i < records.size(); ++i) {            maxN = max(maxN, records[i][0]);            maxN = max(maxN, records[i][1]);        }        ++maxN;     // 编号从1开始滴        vector<vector<int> > graph(maxN);        for (int i = 0; i < records.size(); ++i) {            int u = records[i][0], v = records[i][1];            graph[u].push_back(v);        }        // 算法思想,将重的物体指向轻的物体,如果a到b有一条有向路径,则表示a比b重        if (findRouteTo(g1, g2, graph))            return 1;        if (findRouteTo(g2, g1, graph))            return -1;        return 0;    }    bool findRouteTo(int from, int to, vector<vector<int> >& graph) {        vector<bool> visited(graph.size(), false);        return findRouteHelper(from, to, graph, visited);    }    bool findRouteHelper(int now, int to, vector<vector<int> >& graph, vector<bool>& visited) {        if (now == to)            return true;        for (int i = 0; i < graph[now].size(); ++i) {            int v = graph[now][i];            if (visited[v])                continue;            visited[v] = true;            if (findRouteHelper(v, to, graph, visited))                return true;        }        return false;    }};

C. 第K大的数字(猪厂)

有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。
给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。

测试样例: [1,3,5,2,2],5,3
返回:2

主要是卡时间(虽然直接用STL的快排也过了),考虑用快排的快速划分的部分,如果我们能够将原始数据划分成两部分A和B,且A中所有元素都>=pivot,并且B中所有元素都< pivot,那么:
1. 如果|A| = K的话,直接返回pivot;
2. 如果|A| > K的话,说明要找的数字还在A中;
3. 否则若|A| < K的话,说明要找的数字在|B|中,现在只需要返回|B|中第K-|A|大的数字即可。

class Finder {public:    int findKth(vector<int> v, int n, int K) {        return findHelper(v, 0, n-1, K);    }    int findHelper(vector<int>& v, int left, int right, int K) {        int margin = quick_partition(v, left, right);        int left_size = margin - left + 1;        if (left_size == K)            return v[margin];        if (left_size > K)            return findHelper(v, left, margin-1, K);        return findHelper(v, margin+1, right, K - left_size);    }    int quick_partition(vector<int>& v, int left, int right) {        int rand_select = rand() % (right-left+1) + left;        swap(v[right], v[rand_select]);        int pivot = v[right];        int margin = left - 1;        for (int i = left; i <= right; ++i)            if (v[i] >= pivot)                swap(v[++margin], v[i]);        return margin;    }};

完整的代码(包括测试的代码)放在这里:http://paste.ubuntu.com/15575882/

D. 自己手写快速排序

其实有了上面那个快速划分数组的函数,加多几行就可以写成自己的快速排序了!!!

int quick_partition(vector<int>& v, int left, int right) {    int rand_select = rand() % (right-left+1) + left;    swap(v[right], v[rand_select]);    int pivot = v[right];    int margin = left - 1;    for (int i = left; i <= right; ++i)        if (v[i] <= pivot)            swap(v[++margin], v[i]);    return margin;}// 从小到大排序void quick_sort(vector<int>& v, int left, int right) {    if (left < right) {        int mid = quick_partition(v, left, right);        quick_sort(v, left, mid-1);        quick_sort(v, mid+1, right);    }}

完整的代码(包括测试代码)放在这:http://paste.ubuntu.com/15575909/

【未完待续】

0 0