1 比較重量

给定两颗钻石的编号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) {
// write code here
}
};

思路:有向图。给定起点和重点。求是否存在路径

1.1 第1次提交 错误 结果超时

题目说没有违例数据。所以没有考虑反复数据和矛盾数据,暴力搜

class Cmp {
public:
int cmp(int g1, int g2, vector<vector<int> > records, int n) {
// write code here
// 转换为邻接表
vector<int> tempVector;
vector< vector<int> > graph;
graph.resize(n+1, tempVector);
for (int i = 0; i < records.size(); i++) {
int u = records[i][0];
int v = records[i][1];
graph[u].push_back(v);
} int curStart = g1; for(int i = 0; i <graph[curStart].size(); i++){
if(graph[curStart][i] == g2) // 直接相连的情况
return 1; // return
else {
curStart = graph[curStart][i]; // 下个要訪问的邻接点
i = -1; // 继续循环。又一次计数
}
}
return -1; // return
}
};

1.2 第2次提交 错误 递归过深

依旧没考虑反复数据和矛盾数据。深度优先搜索,错误提示发生段错误,可能是数组越界,堆栈溢出。递归调用层过多,可是后来发现是ret的返回值推断错了,坑

int dfs(vector<vector<int> >& graph, int start, int end){
if(start == end) return 1;
for(int i = 0; i < graph[start].size(); ++i){
int ret = dfs(graph, graph[start][i], end);
if(ret){ // 这里推断条件应该改为ret == 1
return 1;
}
}
return -1;
} int cmp(int g1, int g2, vector<vector<int> > records, int n) {
// write code here
// 转换为邻接表
vector<int> tempVector;
vector< vector<int> > graph;
graph.resize(n+1, tempVector);
for (int i = 0; i < records.size(); i++) {
int u = records[i][0];
int v = records[i][1];
graph[u].push_back(v);
}
int ret = dfs(graph, g1, g2);
return ret; }

1.3 终于提交 AC

中间直接提交“return 1”的错误代码时。系统给出提示。測试用例有反复数据比如[5,8][5,8],也有不可能数据比如[5,5],除此之外还要考虑无法判定的情况,这类情况包括是否有环路情况比如1<2<3<1等。还包括双向均不连通的情形。

终于提交的版本号:


// 有向图,给定起点终点。求是否存在路径
#include <vector>
#include <map>
using namespace std; vector<bool> mark; // 标记start节点是否已经有链表,有则直接push。否则申请vector再push
class Cmp{
public:
// 递归找start到end是否存在路径
int dfs(map<int, vector<int> >& graph, int start, int end){
if(start == end) return 1;
for(int i = 0; i < graph[start].size(); ++i){
int ret = dfs(graph, graph[start][i], end);
if(ret == 1){
return 1;
}
}
return -1;
} // 输入有反复,比如[5,8].....[5,8]反复压入造成递归规模增长
// 压入前推断当前start顶点的数组中是否已有,是则去掉,否则压入
bool isExisted(vector<int>& v, int value){
for(int i =0; i < v.size(); ++i){
if(value == v[i])
return true;
}
return false;
}
int cmp(int g1, int g2, vector<vector<int> > records, int n) {
// write code here
// 转换为邻接表
map<int, vector<int> > graph; // 编号不连续。节省内存
mark.resize(n+1, false); // mark初始化为false
for (int i = 0; i < records.size(); i++) {
int u = records[i][0];
int v = records[i][1];
// 去掉矛盾数据,比如[5,5]
if(u == v) continue;
if(!mark[u]){ // 当前start点没链表,也肯定不存在反复数据
mark[u] = true;
vector<int> tempVec;
tempVec.push_back(v);
graph[u] = tempVec;
} else { // 当前start有链表。继续推断是否有反复数据
if(!isExisted(graph[u], v)){
graph[u].push_back(v);
}
}
}
// 无法判定的情况,包括了环路的矛盾情况
int ret1 = dfs(graph, g1, g2);
int ret2 = dfs(graph, g2, g1);
if(ret1 == ret2) {return 0;}
return ret1;
}
};

附: 前两次提交时用的測试程序

#include <vector>
#include <iostream> using namespace std;
/*
// 2. 发生段错误。可能是数组越界,堆栈溢出(递归调用层数太多)
int dfs(vector< vector<int> >& graph, int start, int end){
if(start == end) return 1;
for(int i = 0; i < graph[start].size(); ++i){
int ret = dfs(graph, graph[start][i], end);
if(ret){ //事实上是错在这里了,推断条件应该改为ret == 1
return 1;
}
}
return -1;
}
*/ // 3. 改进的dfs int main() {
vector< vector<int> > records;
vector<int> tempVector;
vector< vector<int> > graph;
int n = 4;
int start = 2;
int end = 3;
// 原始输入
tempVector.push_back(1);
tempVector.push_back(2);
records.push_back(tempVector); tempVector.clear();
tempVector.push_back(2);
tempVector.push_back(4);
records.push_back(tempVector); tempVector.clear();
tempVector.push_back(1);
tempVector.push_back(3);
records.push_back(tempVector); tempVector.clear();
tempVector.push_back(4);
tempVector.push_back(3);
records.push_back(tempVector); /*
// for test : print original input
for (int u = 0; u < records.size(); u++) {
for (int v = 0; v < records[u].size(); v++) {
cout << records[u][v] << " ";
}
cout << endl;
}
*/ // 转换为邻接表
tempVector.clear();
graph.resize(n+1, tempVector);
for (int i = 0; i < records.size(); i++) {
int u = records[i][0];
int v = records[i][1];
graph[u].push_back(v);
} /*
// for test : print used input
for (int u = 0; u < graph.size(); u++) {
for (int v = 0; v < graph[u].size(); v++) {
cout << graph[u][v] << " ";
}
cout << endl;
}
*/ // 1. 超时
/*
int curStart = start; for(int i = 0; i < graph[curStart].size(); i++){
if(graph[curStart][i] == end) // 直接相连的情况
{
cout << 1; // return
break;
}
else {
curStart = graph[curStart][i]; // 下个要訪问的邻接点
i = -1; // 继续循环,又一次计数
}
}
cout << -1; // return
*/ // 2.调用
int g1 = start;
int g2 = end; int ret = dfs(graph, g1, g2);
cout << ret;
return 0;
}

2 二叉树

有一棵二叉树,树上每一个点标有权值。权值各不同样。请设计一个算法算出权值最大的叶节点到权值最小的叶节点的距离。二叉树每条边的距离为1,一个节点经过多少条边到达还有一个节点为这两个节点之间的距离。

给定二叉树的根节点root,请返回所求距离。

/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/ class Tree {
public:
int getDis(TreeNode* root) {
// write code here
}
};

思路:先求最大、最小的叶节点,然后找两个节点的最低公共祖先(LCA),然后求两个节点到LCA的距离和

2.1 第1次提交 错误

第1次提交的时候脑残了。推断叶子节点的条件写错了。叶子节点应该是无左孩也无右孩,所以要在当前层推断。然后继续递归。

2.2 终于提交 AC

/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
#include <climits>
#include <iostream>
using namespace std; int current_min;
int current_max; class Tree {
public:
// 中序遍历找最小、最大叶子节点
void findMinMax(TreeNode* root){
if(root == NULL) return; if(NULL == root->left && NULL == root->right){
if(root->val < current_min) current_min = root->val;
if(root->val > current_max) current_max = root->val;
} findMinMax(root->left);
findMinMax(root->right);
} // LCA
TreeNode* findLCA(TreeNode* root, int min, int max){
if(root == NULL) return NULL;
if(root->val == min || root->val == max)
return root;
TreeNode* left_lca = findLCA(root->left, min, max);
TreeNode* right_lca = findLCA(root->right, min, max);
if(left_lca != NULL && right_lca != NULL)
return root;
return left_lca != NULL ? left_lca : right_lca;
} // return level of node, root level is 0.
int findLevel(TreeNode* root, int val){
if(root == NULL) return -1;
if(root->val == val) return 0;
int level = findLevel(root->left, val);
if(level == -1){
level = findLevel(root->right, val);
}
if(level != -1)
return level + 1;
return -1;
} int getDis(TreeNode* root) {
// write code here
current_min = INT_MAX;
current_max = INT_MIN;
findMinMax(root);
TreeNode* lca = findLCA(root, current_min, current_max);
int lev_lca = findLevel(root, lca->val);
int lev_min = findLevel(root, current_min);
int lev_max = findLevel(root, current_max);
return lev_min + lev_max - 2*lev_lca; }
};

3 寻找第K大

有一个整数数组。请你依据高速排序的思路,找出数组中第K大的数。

给定一个整数数组a,同一时候给定它的大小n和要找的K(K在1到n之间)。请返回第K大的数。保证答案存在。

測试例子:

[1,3,5,2,2],5,3

返回:2

class Finder {
public:
int findKth(vector<int> a, int n, int K) {
// write code here
}
};

直接思路就是排序,然后找相应位置,比較简单

3.1 复习 高速排序

// 高速排序, 交换次数较少的实现
#include <iostream>
#include <algorithm>
using namespace std; void printArrayInt(int arr_int[], int size){
for(int i = 0; i < size; ++i){
cout << arr_int[i] << " ";
}
cout << endl;
} //划分操作
int partition(int arr[], int start, int end) {
int i = start - 1;//指向开头
int j = end;//指向结尾
int pivot = arr[end];
while(true){
while(i < end && arr[++i] < pivot);//从前到后 第一个比 基准(x)大的数。 i指向该数
while(j > start && arr[--j] > pivot);//从后向前找到第一个比 基准(x)小的数。j指向该数
if(i >= j)
break;
swap(arr[i], arr[j]);
}
swap(arr[i], arr[end]);
return i;
} void quickSort(int arr_int[], int start, int end){
if(start < end){
int partition_index = partition(arr_int, start, end);
quickSort(arr_int, start, partition_index - 1);
quickSort(arr_int, partition_index + 1, end);
}
} int main()
{ int arr_int[] = {10, 7, 8, 9, 1, 5};
int arr_size = sizeof(arr_int) / sizeof(arr_int[0]);
quickSort(arr_int, 0, arr_size-1); return 0;
}

3.2 第1次提交 快排 AC:

#include <iostream>
#include <algorithm>
using namespace std; class Finder {
public: //划分操作
int partition(int arr[], int start, int end) {
int i = start - 1;//指向开头
int j = end;//指向结尾
int pivot = arr[end];
while(true){
while(i < end && arr[++i] < pivot);//从前到后 第一个比 基准(x)大的数。 i指向该数
while(j > start && arr[--j] > pivot);//从后向前找到第一个比 基准(x)小的数。 j指向该数
if(i >= j)
break;
swap(arr[i], arr[j]);
}
swap(arr[i], arr[end]);
return i;
} void quickSort(int arr_int[], int start, int end){
if(start < end){
int partition_index = partition(arr_int, start, end);
quickSort(arr_int, start, partition_index - 1);
quickSort(arr_int, partition_index + 1, end);
}
} int findKth(vector<int> a, int n, int K) {
int* arr_int = new int[n];
for(int i = 0; i < n; ++i){
arr_int[i] = a[i];
}
quickSort(arr_int, 0, n - 1);
return arr_int[n - K];
}
};

快排的时间复杂度为O(nlogn)。 比較慢,

更快的方法:

创建一个大小为k的数据容器,存储k个最大的数字,过程:

a) 若容器中数字不足k个,则放入容器

b) 若容器已经满了,则找出k个数字中最小的值,若当前值比容器中的最小值大,则替换容器中的最小值。否则抛弃当前值。

容器满了之后。要做三件事:

(1)在k个整数中找到最小值

(2)有可能删除最小值

(3)有可能插入新的值,并保证k个整数是已排序。

所以用二叉树实现容器,则三种操作可在O(logk)时间内完毕,对于n个数字,总的时间是O(nlogk)

由于每次都要取出最小值。且容器保持排序状态。所以想到最小堆, 直接使用STL中基于红黑树的multiset

3.3 第2次提交 最小堆 AC

// 终于提交:
#include <vector>
#include <set>
class Finder {
public:
typedef multiset<int> MinHeapInt; void find_kth_max_int(const vector<int>& vec_int, MinHeapInt& largestNumbers, int k){ largestNumbers.clear(); if(k <= 0 || vec_int.size() < k)
return; vector<int>::const_iterator iter = vec_int.begin();
for(; iter != vec_int.end(); ++iter){
// 最小堆未满时
if(largestNumbers.size() < k){
largestNumbers.insert(*iter);
}
else{
// 最大堆已满
MinHeapInt::iterator iterFirst = largestNumbers.begin();
// 当前元素大于堆中最小值时。替换
if(*iter > *(largestNumbers.begin())){
largestNumbers.erase(iterFirst);
largestNumbers.insert(*iter);
}
}
}
} int findKth(vector<int> a, int n, int K) {
// write code here
MinHeapInt largestNumbers;
find_kth_max_int(a, largestNumbers, K);
return *(largestNumbers.begin());
}
};

附: 測试程序

#include <vector>
#include <set>
#include <iostream>
using namespace std; typedef multiset<int> MinHeapInt; void find_kth_max_int(const vector<int>& vec_int, MinHeapInt& largestNumbers, int k){ largestNumbers.clear(); if(k <= 0 || vec_int.size() < k)
return; vector<int>::const_iterator iter = vec_int.begin();
for(; iter != vec_int.end(); ++iter){
// 最小堆未满时
if(largestNumbers.size() < k){
largestNumbers.insert(*iter);
}
else{
// 最大堆已满
MinHeapInt::iterator iterFirst = largestNumbers.begin();
// 当前元素大于堆中最小值时,替换
if(*iter > *(largestNumbers.begin())){
largestNumbers.erase(iterFirst);
largestNumbers.insert(*iter);
}
}
}
} int main(){
vector<int> data;
data.push_back(10);
data.push_back(1);
data.push_back(7);
data.push_back(3);
data.push_back(4);
data.push_back(8);
data.push_back(5);
data.push_back(11);
data.push_back(12);
MinHeapInt largestNumbers;
int k = 4;
find_kth_max_int(data, largestNumbers, k);
// for test
multiset<int>::const_iterator iter = largestNumbers.begin();
for(; iter!=largestNumbers.end(); ++iter){
cout << *iter << " ";
}
cout << endl;
cout << "第" << k << "大的数为" << *(largestNumbers.begin()) << endl;
return 0;
}

3.4 第3次提交 半排序 AC

中间提交了两次。当中一次发现少了return语句,由于半排序的递归过程也是要写return的,一旦到达kth_max位置,就直接return了。第二次是发现查错了kth_max的下标。

// 半排序思想
/*
快排的切割过程返回pivot_index位置时(从0计数)。
左側有pivot_index 个比pivot_value小的数。
右側有n - pivot_index-1个比pivot_value大的数。
所以pivot_value本身是第n-pivot_index大的数,
当pivot_index == n-k时,pivot_value为第k大的数
所以kth_max的index为n-k,设为kth_index 递归过程相似于二分查找。当pivot_index==kth_index时,程序结束,返回结果
否则,继续在kth max所在的左側或右側继续分治排序(相似于二分查找)
*/ #include <algorithm>
using namespace std;
class Finder {
public:
int partition(int arr_int[], int start, int end){
int pivot_value = arr_int[end];
int i = start - 1;
int j = end;
while(true){
while(i < end && arr_int[++i] < pivot_value);
while(j > start && arr_int[--j] > pivot_value);
if(i >= j)
break;
swap(arr_int[i], arr_int[j]);
}
swap(arr_int[i], arr_int[end]);
return i;
} int quick_sort_find_kth_max(int arr_int[], int start, int end, int k){ int pivot_index = partition(arr_int, start, end);
// kth max 在pivot_index左側,右側都比kth max大,不用管,排左側
if(pivot_index > k){
return quick_sort_find_kth_max(arr_int, start, pivot_index - 1, k);
}
// kth max 在pivot_index右側,左側逗比kth max小。不用管。排右側
else if(pivot_index < k){
return quick_sort_find_kth_max(arr_int, pivot_index + 1, end, k);
}
else{
return arr_int[pivot_index];
}
} int findKth(vector<int> a, int n, int K) {
// write code here
int* arr_int = new int[n];
for(int i = 0; i < n; ++i){
arr_int[i] = a[i];
}
return quick_sort_find_kth_max(arr_int, 0, n-1, n-K);// 1,2,3。第3大的是1。所以kth max的index是n-k }
};

网易 2016 实习研发project师 3道 编程题的更多相关文章

  1. 网易2016年研发project师编程题(2)

    序 网易互联网的实习笔试立即就開始了,做几个练习题熟悉熟悉~嘿嘿~ 题目一: 小易的升级之路 小易常常沉迷于网络游戏.有一次,他在玩一个打怪升级的游戏,他的角色的初始能力值为 a.在接下来的一段时间内 ...

  2. 寻找第K大 网易2016实习研发工程师编程题

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

  3. 网易2016 实习研发工程师 [编程题]寻找第K大 and leetcode 215. Kth Largest Element in an Array

    传送门 有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数. 给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在. 测试样例: [1,3,5, ...

  4. 网易2016研发project师笔试题

    网易2016研发project师笔试题 2015/12/9 11:25(网上收集整理的,參考答案在后面,若有错误请大神指出) 1. 运行指令find / -name "test.c" ...

  5. 网易游戏2015年暑期实习生面试经历-游戏研发project师

    首先,我还是先介绍一下网易游戏吧.引用别人的一段话 作者:王选易.出处: http://www.cnblogs.com/neverdie/ 欢迎转载 .也请保留这段声明.假设你喜欢这篇文章,请点[推荐 ...

  6. 百度2016研发project师笔试题(四)

    百度2016研发project师笔试题(四) 2015/12/8 10:42(网上收集整理的,參考答案在后面.若有错误请大神指出) 1. 关于MapReduce的描写叙述错误的是() A. 一个Tas ...

  7. 阿里巴巴2014研发project师实习生面试经历

    java研发project师的初面是在上周三进行的,终于结果到了晚上才出,而没有通过的则是一结束网上就更新了状态.之后阿里通知这周三,也就是今天进行二面. 凑巧的是今早被舍友吵醒,中午那个困啊,但没时 ...

  8. 2014阿里巴巴研发project师暑期实习生面试经验

    2014阿里巴巴研发project师暑期实习生面试经验 作者:林子 Blog:  http://blog.csdn.net/u013011841 时间:2014年8月 出处:http://blog.c ...

  9. 最美应用-从Android研发project师的角度之[最美时光]

    最美应用-从Android研发project师的角度之最美时光 @author ASCE1885的 Github 简书 微博 CSDN 近期发现最美应用这样一个站点.它会定期推介一些非常有意思的app ...

随机推荐

  1. Drupal 开发必备利器

    http://drupalchina.cn/node/3436 转自 测试模块.主题.发行版的网站: http://simplytest.me/ Drupal API: https://api.dru ...

  2. hbase源码系列(二)HTable 探秘

    hbase的源码终于搞一个段落了,在接下来的一个月,着重于把看过的源码提炼一下,对一些有意思的主题进行分享一下.继上一篇讲了负载均衡之后,这一篇我们从client开始讲吧,从client到master ...

  3. python多线程同步机制condition

    #!/usr/bin/env python# -*- coding: utf-8 -*- import threadingimport time def customer(cond): t = thr ...

  4. python List的一些相关操作

    把一些基础的东西归类整理,作记录. 添加元素 a=[7,8,9,10] a.append('a') #在最后位置添加 a.insert(1,'b') #在指定位置添加     删除元素 del a[1 ...

  5. Redis的内存回收机制

    Redis的内存回收机制 2018年01月16日 17:11:48 chs007chs 阅读数:1172   Redis的内存回收机制主要体现在一下两个方面: 删除过期时间的键对象 删除过期键对象 : ...

  6. Spring Boot 自定义属性 以及 乱码问题

    自定义属性 使用随机数及自定义配置类 中文乱码问题 1添加配置 2设置文件类型 1IDEA 2eclipse 自定义属性 application.properties提供自定义属性的支持,这样我们就可 ...

  7. PCL特征点与配准(1)

    关于输入一个具体的物体的点云,从场景中找出与该物体点云相匹配的,这种方法可以用来抓取指定的物体等等,具体的代码的解释如下,需要用到的一些基础的知识,在之前的博客中都有提及,其中用到的一些方法可以翻阅前 ...

  8. 微信小程序——收起和查看更多功能

    项目中做一些列表的时候,可能会需要做到 查看更多 及 收起功能,如下图所示: 大概的需求就是默认只显示2条,点击[查看更多]显示全部,点击[收起]还原. 实现的方法千万种.我来讲一下我的实现思路: 1 ...

  9. Qt 程序打包发布总结

    1.  概述 当我们用QT写好了一个软件,要把你的程序分享出去的时候,不可能把编译的目录拷贝给别人去运行.编译好的程序应该是一个主程序,加一些资源文件,再加一些动态链接库,高大上一些的还可以做一个安装 ...

  10. svn解决不能clean的方法

    http://blog.csdn.net/victory08/article/details/42100325 svn执行clean up后出现提示:svn cleanup failed–previo ...