深信服2018校园招聘C++工程师编程题 - 题解
2017-11-30 01:14
501 查看
深信服2017的校园招聘的题目和这次的几乎一样,不知道贵公司是什么样的想法。做过2017的题目的同学应该会比较占优势。题目不难,比较考验编程的技巧与准确度。
冒泡法有两个循环,最里面的循环是排序用的,而最外面的循环是排序需要的趟数,排序的趟数也就是链表的长度减一(排这么多趟一定可以排好序,但是不一定需要这么多);
这样一来就要求链表的长度,不好,注意到,如果排一趟序无可交换的元素,那么就说明链表已经排好序了,所以,利用这个原理可以设置一个标志变量
模板支持普通字符(
请完成该函数代码:
如果
这个题还要注意一点,题目给出的输入函数会把
某个位置处的棋子还有多少口气的计算方法(简化计算):从该位置出发,向四个方向遍历,允许拐弯,但不允许走斜线,如果遇到边线和对方的棋子,则认为不能继续往前走。遍历完成后统计遍历过程中遇到的未落子的位置个数,该位置个数即出发点棋子的气的数目。
如果遇到边线和对方的棋子和自己的棋子,则认为不能继续往前走,那么广搜一下,看看目标位置能到的位置有多少个,但是我只过了66.6%66.6%的数据,不知道哪里出了问题也不知道我是不是理解错题目了,于是,我计算了下围棋真正的气。
首先找到该棋子的连通块,然后统计连通块外围棋子的个数就是该棋子的气。
找连通块我也没有用广搜,用的是一种扩散的想法,代码类似于这样子:往目标棋子滴一滴墨水,然后一秒钟后就会往外扩散,然后下一秒往外扩散,直到扩散不了。 具体实现看代码。
第一题:堆排序
题目:
函数heap_sort使用堆排序的方法对数组
arr进行排序,排序后的数据为降序,相关的代码如下,请补充确实的部分。
// 调整为小顶堆 static void heap_arrange(int arr[], int cur, int cnt) //调整为小顶堆 { int heaptop_val = arr[cur]; //堆顶的值 while (cur < cnt) { int left = 2 * cur + 1; int right = 2 * cur + 2; int min = -1; int min_val = ________; if (left < cnt && arr[left] < min_val) { //检查是否比左节点大 min = left; min_val = arr[left]; } if (right < cnt && arr[right] < min_val) {//检查是否比右节点大 min = right; } if (min == ________) break; arr[cur] = ________; cur = ________; } arr[cur] = ________; }
解析:
堆排序的原理就是树上的插入排序,因此,堆排序的原理还是要准确理解的,这样才能填出来,既然是插入排序,那么,min_val就一直是
heaptop_val;
min_val与左右两个孩子比较得出最小的那个元素,如果最小的元素还是
heaptop_val那么
min的值就没变,仍然是
-1,这个时候插入排序结束,找到了插入的位置就跳出;否则的话就把左右孩子最小的那个结点赋值给当前节点,故
arr[cur] = arr[min],更新当前节点
cur = min;最后,把
heaptop_val调到要插入的位置,即
arr[cur] = heaptop_val。
代码:
// 调整为小顶堆 static void heap_arrange(int arr[], int cur, int cnt) //调整为小顶堆 { int heaptop_val = arr[cur]; //堆顶的值 while (cur < cnt) { int left = 2 * cur + 1; int right = 2 * cur + 2; int min = -1; int min_val = heaptop_val; if (left < cnt && arr[left] 18998 < min_val) { //检查是否比左节点大 min = left; min_val = arr[left]; } if (right < cnt && arr[right] < min_val) {//检查是否比右节点大 min = right; } if (min == -1) break; arr[cur] = arr[min]; cur = min; } arr[cur] = heaptop_val; }
第二题:单链表冒泡排序
题目:
请实现list_sort,使用冒泡法将
head指向的链表按
val的值大小排成升序。
struct node { int val; struct node *next; }; static void list_sort(struct node *head) { }
解析:
冒泡法大家都很熟悉,单链表来实现无非就是考到链表的基本操作,但是这里我们简化一下代码,也就是说,我们是采用交换两结点的值的做法而不是交换两个结点。冒泡法有两个循环,最里面的循环是排序用的,而最外面的循环是排序需要的趟数,排序的趟数也就是链表的长度减一(排这么多趟一定可以排好序,但是不一定需要这么多);
这样一来就要求链表的长度,不好,注意到,如果排一趟序无可交换的元素,那么就说明链表已经排好序了,所以,利用这个原理可以设置一个标志变量
f来维护一趟排序中是否有元素的交换,一趟排序后判一下
f就可以知道是否跳出最外层的循环.
代码:
static void list_sort(struct node *head) { //TODO: while (true) { int f = true; struct node * p = head; for (;p && p->next; p = p->next) if (p->val > p->next->val) { f = false; int tmp = p->val; p->val = p->next->val; p->next->val = tmp; } if (f) break; } }
第三题:二进制位反序
题目:
编写函数reverse,将
val(32位无符号整数)的二进制位反序,比如,如果
val的二进制表示为
1011000011111111,反序后
val的二进制表示为
1111111100001101。
unsigned int reverse(unsigned int num) { }
解析:
做法很多,我的做法是把一边去掉最后一位数,一边生成反序后的十进制数。代码:
unsigned int reverse(unsigned int num) { //TODO: unsigned int ret = 0; for (int i = 0; i < 32; i++, num /= 2) ret = ret * 2 + num % 2; return ret; }
第四题
题目:
函数match检查字符串
str是否匹配模板
pattern,匹配则返回
0,否则返回
-1。
模板支持普通字符(
a-z0-9A-Z)及通配符
?和
*,普通字符匹配该字符本身,
?匹配任意一个字符,
*匹配任意多个字符。比如字符串
abc对下述模板的匹配结果为:
模板 | -结果 |
---|---|
abc | 0 |
a* | 0 |
a*c | 0 |
a*b | -1 |
ab? | 0 |
a? | -1 |
int match(const char *str, const char *pattern) { }
解析:
由于数据不大,故可以暴力递归解决,递归的终止条件是:strlen(str)等于0,并且
strlen(pattern)等于0,这时匹配成功;
strlen(str)和
strlen(pattern)有且只有一个为0,这时匹配失败。
如果
strlen(str)和
strlen(pattern)都不为0,那么继续递归:
pattern[0]为
?,那么就判断
pattern + 1和
str + 1是否匹配;
pattern[0]位
*,那么判断
pattern + 1和
str + i(0<=i<strlen(str)0<=i<strlen(str))里面是否有一个匹配,只要有一个匹配,那么就匹配了,如果所有的都不匹配,那么就不匹配了;
pattern[0]为字母或数字,那么就判断
str[0]和
pattern[0]是否相等,如果不相等就不匹配,如果相等,那么还要判断
pattern + 1和
str + 1是否匹配。
这个题还要注意一点,题目给出的输入函数会把
\n也会加入到字符串中,因此可以先把
\n去掉,不去掉也可以,那么判断
pattern[0]的时候就要注意顺序,先判断
*和
?。
代码:
int match(const char *str, const char *pattern) { //TODO: int str_len = strlen(str), pattern_len = strlen(pattern); if (!str_len && !pattern_len) return 0; if (!pattern_len || !str_len) return -1; if (pattern[0] == '*') { for (int i = 0; str[i]; i++) if (0 == match(str + i, pattern + 1)) return 0; return -1; } else if (pattern[0] == '?') { return match(str + 1, pattern + 1); } else { return pattern[0] == str[0] ? match(str + 1, pattern + 1) : -1; } }
DIY数据:
// input abcd ********************* // output match
第五题:围棋的“气”
题目:
函数calc计算围棋盘位置
(x,y)处的棋子还有多少口气。
某个位置处的棋子还有多少口气的计算方法(简化计算):从该位置出发,向四个方向遍历,允许拐弯,但不允许走斜线,如果遇到边线和对方的棋子,则认为不能继续往前走。遍历完成后统计遍历过程中遇到的未落子的位置个数,该位置个数即出发点棋子的气的数目。
解析:
首先,这个简化计算描述就不清楚,注意这句话:如果遇到边线和对方的棋子,则认为不能继续往前走,那么遇到自己的棋子怎么办呢?这里值得思考一下;如果遇到边线和对方的棋子和自己的棋子,则认为不能继续往前走,那么广搜一下,看看目标位置能到的位置有多少个,但是我只过了66.6%66.6%的数据,不知道哪里出了问题也不知道我是不是理解错题目了,于是,我计算了下围棋真正的气。
首先找到该棋子的连通块,然后统计连通块外围棋子的个数就是该棋子的气。
找连通块我也没有用广搜,用的是一种扩散的想法,代码类似于这样子:往目标棋子滴一滴墨水,然后一秒钟后就会往外扩散,然后下一秒往外扩散,直到扩散不了。 具体实现看代码。
代码:
int calc(struct weiqi *wq, int y, int x) { //TODO: if (wq->board[x][y] == NONE) return -1; enum color nowChess = wq->board[x][y]; int dirx[] = {0, 0, 1, -1}; int diry[] = {1, -1, 0, 0}; int used[19][19] = {0}; used[x][y] = 1; while (true) { int f = 0; for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { if (used[i][j]) { for (int k = 0; k < 4; k++) { int tx = i + dirx[k]; int ty = j + diry[k]; if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 && wq->board[tx][ty] == nowChess && !used[tx][ty]) used[tx][ty] = 1, f = 1; } } } } if (!f) break; } int ans = 0; for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { if (used[i][j] == 1) { for (int k = 0; k < 4; k++) { int tx = i + dirx[k]; int ty = j + diry[k]; if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 && wq->board[tx][ty] == NONE && used[tx][ty] != 1) used[tx][ty] = 2; } } } } for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { ans += (used[i][j] == 2); } } return ans; }
DIY数据:
// input 0000000000000000000 0011100000000000000 0001000000000000000 0001111000000000000 0000001000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000000000 0000000000000110000 0000000000000000000 0000000000000000000 0000000000000000000 2,1 // output 16
五个题完整代码:
一、
#include <stdio.h> #include <stdlib.h> #include <assert.h> static void heap_arrange(int arr[], int cur, int cnt); static int heap_verify(int arr[], int cnt) { int i; for (i = 0; i < cnt / 2; ++i) { int lhs = 2 * i + 1; int rhs = 2 * i + 2; if (lhs < cnt && arr[i] > arr[lhs]) { fprintf(stderr, "arr[%d]:%d > arr[%d]:%d\n", i, arr[i], lhs, arr[lhs]); return -1; } if (rhs < cnt && arr[i] > arr[rhs]) { fprintf(stderr, "arr[%d]:%d > arr[%d]:%d\n", i, arr[i], rhs, arr[rhs]); return -1; } } return 0; } static void heap_print(int arr[], int cnt) { int layer = 0, num = 0; for (layer = 0; num < cnt; ++layer) { int i = 0; for (i = 0 ; i < (1 << layer) && num < cnt ; ++i) printf("%3d ", arr[num++]); printf("\n"); } } static void heap_sort(int arr[], int cnt) { int i; printf("origin:\n"); heap_print(arr, cnt); // 建堆 for (i = cnt / 2 - 1; i >= 0; --i) { heap_arrange(arr, i, cnt); } printf("make heap:\n", i); heap_print(arr, cnt); assert(heap_verify(arr, cnt) == 0); for (i = cnt - 1; i > 0; --i) { int tmp; tmp = arr[0]; arr[0] = arr[i]; arr[i] = tmp; printf("sort i=%d\n", i); heap_print(arr, cnt); heap_arrange(arr, 0, i); heap_print(arr, cnt); assert(heap_verify(arr, i) == 0); } printf("sorted:\n"); heap_print(arr, cnt); } static int input(int **arr, int *size) { int i; int ret; ret = fscanf(stdin, "%d\n", size); if (ret != 1) return -1; *arr = (int *)malloc(sizeof(int) * (*size)); for (i = 0; i < *size; ++i) { fscanf(stdin, "%d ", &(*arr)[i]); } return 0; } int main(int argc, char *argv[]) { int *arr = NULL; int cnt = 0; int i; if (input(&arr, &cnt) < 0) { fprintf(stderr, "input error\n"); return 0; } heap_sort(arr, cnt); return 0; } // 调整为小顶堆 static void heap_arrange(int arr[], int cur, int cnt) //调整为小顶堆 { int heaptop_val = arr[cur]; //堆顶的值 while (cur < cnt) { int left = 2 * cur + 1; int right = 2 * cur + 2; int min = -1; int min_val = heaptop_val; if (left < cnt && arr[left] < min_val) { //检查是否比左节点大 min = left; min_val = arr[left]; } if (right < cnt && arr[right] < min_val) {//检查是否比右节点大 min = right; } if (min == -1) break; arr[cur] = arr[min]; cur = min; } arr[cur] = heaptop_val; }
二、
#include <stdio.h>
#include <malloc.h>
struct node {
int val;
struct node *next;
};
static void list_sort(struct node *head);
struct node *list_create(int arr[], int size)
{
struct node *head = NULL;
int i;
for (i = size - 1; i >= 0; --i) {
struct node *p = (struct node *)malloc(sizeof(struct node));
p->val = arr[i];
p->next = head;
head = p;
}
return head;
}
static void list_print(struct node *head)
{
for (; head; head = head->next) {
printf("%d", head->val);
if (head->next)
printf(" ");
}
printf("\n");
}
static void list_free(struct node *head)
{
struct node *next;
while (head) {
next = head->next;
free(head);
head = next;
}
}
static int input(int **arr, int *size)
{
int i;
int ret;
ret = fscanf(stdin, "%d\n", size);
if (ret != 1)
return -1;
*arr = (int *)malloc(sizeof(int) * (*size));
for (i = 0; i < *size; ++i) {
fscanf(stdin, "%d ", &(*arr)[i]);
}
return 0;
}
int main(int argc, char *argv[])
{
struct node *head;
int *arr = NULL;
int size = 0;
if (input(&arr, &size) < 0) {
fprintf(stderr, "input error\n");
return 0;
}
head = list_create(arr, size);
list_sort(head);
list_print(head);
list_free(head);
free(arr);
return 0;
}
static void list_sort(struct node *head) { //TODO: while (true) { int f = true; struct node * p = head; for (;p && p->next; p = p->next) if (p->val > p->next->val) { f = false; int tmp = p->val; p->val = p->next->val; p->next->val = tmp; } if (f) break; } }
三、
#include <stdio.h>
#include <string.h>
unsigned int reverse(unsigned int num) { //TODO: unsigned int ret = 0; for (int i = 0; i < 32; i++, num /= 2) ret = ret * 2 + num % 2; return ret; }
int main(int argc, char *argv[])
{
unsigned int num = 0;
unsigned int ret = 0;
if (1 != fscanf(stdin, "0x%x", &num)) {
fprintf(stderr, "input error\n");
return 0;
}
ret = reverse(num);
printf("%08x\n", ret);
return 0;
}
四、
#include <stdio.h> #include <string.h> #include <ctype.h> #include <malloc.h> int match(const char *str, const char *pattern) { //TODO: int str_len = strlen(str), pattern_len = strlen(str); if (!str_len && !pattern_len) return 0; if (!pattern_len || !str_len) return -1; if (pattern[0] == '*') { for (int i = 0; str[i]; i++) if (0 == match(str + i, pattern + 1)) return 0; return -1; } else if (pattern[0] == '?') { return match(str + 1, pattern + 1); } else { return pattern[0] == str[0] ? match(str + 1, pattern + 1) : -1; } } int input(char **src, char **ptn) { char buf[10240]; *src = NULL; *ptn = NULL; if (fgets(buf, sizeof(buf), stdin) == 0) goto failed_; *src = strdup(buf); if (fgets(buf, sizeof(buf), stdin) == 0) goto failed_; *ptn = strdup(buf); return 0; failed_: if (*src) free(*src); if (*ptn) free(*ptn); *src = NULL; *ptn = NULL; return -1; } int main(int argc, char *argv[]) { char *src = NULL; char *ptn = NULL; if (input(&src, &ptn) < 0) { fprintf(stderr, "error\n"); return 0; } if (match(src, ptn) == 0) { printf("match\n"); } else { printf("unmatch\n"); } return 0; }
五、
#include <stdio.h>
#include <string.h>
enum color {
NONE, WHITE, BLACK, //棋子颜色,NONE表示未落子
};
struct weiqi {
enum color board[19][19]; //棋盘上每个位置的落子
};
int calc(struct weiqi *wq, int y, int x) { //TODO: if (wq->board[x][y] == NONE) return -1; enum color nowChess = wq->board[x][y]; int dirx[] = {0, 0, 1, -1}; int diry[] = {1, -1, 0, 0}; int used[19][19] = {0}; used[x][y] = 1; while (true) { int f = 0; for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { if (used[i][j]) { for (int k = 0; k < 4; k++) { int tx = i + dirx[k]; int ty = j + diry[k]; if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 && wq->board[tx][ty] == nowChess && !used[tx][ty]) used[tx][ty] = 1, f = 1; } } } } if (!f) break; } int ans = 0; for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { if (used[i][j] == 1) { for (int k = 0; k < 4; k++) { int tx = i + dirx[k]; int ty = j + diry[k]; if (tx >= 0 && tx < 19 && ty >= 0 && ty < 19 && wq->board[tx][ty] == NONE && used[tx][ty] != 1) used[tx][ty] = 2; } } } } for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { ans += (used[i][j] == 2); } } return ans; }int input(struct weiqi *wq, int *x, int *y)
{
int row, col;
int ret;
char buf[80];
for (row = 0; row < 19; ++row) {
if (fgets(buf, sizeof(buf), stdin) == NULL)
return -1;
if (strlen(buf) < 19)
return -1;
for (col = 0; col < 19; ++col) {
switch (buf[col]) {
case '0':
wq->board[row][col] = NONE;
break;
case '1':
wq->board[row][col] = WHITE;
break;
case '2':
wq->board[row][col] = BLACK;
break;
default:
return -1;
}
}
}
ret = fscanf(stdin, "%d,%d\n", x, y);
if (ret != 2)
return -1;
for (row = 0 ; row < 19; ++row) {
for (col = 0; col < 19; ++col) {
fprintf(stderr, "%d ", wq->board[row][col]);
}
fprintf(stderr, "\n");
}
fprintf(stderr, "x = %d, y = %d\n", *x, *y);
return 0;
}
int main()
{
struct weiqi wq;
int x = 0, y = 0;
int cnt;
memset(&wq, 0, sizeof(wq));
if (input(&wq, &x, &y) < 0) {
fprintf(stderr, "error!\n");
return 1;
}
cnt = calc(&wq, x, y);
printf("%d\n", cnt);
return 0;
}
相关文章推荐
- 51信用卡2018校园招聘编程题学习
- 牛客网-网易2018校园招聘编程题真题集合-解题思路及源码
- 猎豹移动(金山网络)2015校园招聘(c++工程师)
- 网易2018校园招聘编程题真题集合3字符串碎片
- 科大讯飞2018校园招聘9月16号编程题
- 网易2018校园招聘编程题真题集合 (部分)
- 2011金山软件校园招聘 C++开发工程师 笔试题
- 寻找丑数 - 滴滴出行2018校园招聘网申笔试-研发工程师
- 京东2017校园招聘Android研发工程师编程题(二):幸运数
- 整数无序数组求第K大数(暴力|快排) - 滴滴出行2018校园招聘内推笔试-研发工程师
- 网易2018校园招聘编程题真题集合1魔法币
- 给定整数序列求连续子串最大和 - 滴滴出行2018校园招聘内推笔试-研发工程师
- 百度2016校园招聘-开发测试工程师-在线编程题2-比大小
- 阿里2015实习生校园招聘C/C++研发工程师面试经历
- 爱奇艺2018秋季校招C++工程师(第三场)编程题 - 题解
- 爱奇艺2018秋季校招C++工程师(第一场)编程题 - 题解
- xor - 滴滴出行2018校园招聘网申笔试-研发工程师
- 网易2018校园招聘编程题
- 网易2018校园招聘编程题真题集合
- 校园招聘-2017阿里C/C++研发工程师内推笔试编程题