深信服2018校園招聘C++工程師程式設計題
深信服2017的校園招聘的題目和這次的幾乎一樣,不知道貴公司是什麼樣的想法。做過2017的題目的同學應該會比較佔優勢。題目不難,比較考驗程式設計的技巧與準確度。
第一題:堆排序
題目:
函式
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] < 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
()裡面是否有一個匹配,只要有一個匹配,那麼就匹配了,如果所有的都不匹配,那麼就不匹配了;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)
處的棋子還有多少口氣。某個位置處的棋子還有多少口氣的計算方法(簡化計算):從該位置出發,向四個方向遍歷,允許拐彎,但不允許走斜線,如果遇到邊線和對方的棋子,則認為不能繼續往前走。遍歷完成後統計遍歷過程中遇到的未落子的位置個數,該位置個數即出發點棋子的氣的數目。
解析:
首先,這個簡化計算描述就不清楚,注意這句話:如果遇到邊線和對方的棋子,則認為不能繼續往前走,那麼遇到自己的棋子怎麼辦呢?這裡值得思考一下;
如果遇到邊線和對方的棋子和自己的棋子,則認為不能繼續往前走,那麼廣搜一下,看看目標位置能到的位置有多少個,但是我只過了的資料,不知道哪裡出了問題也不知道我是不是理解錯題目了,於是,我計算了下圍棋真正的氣。
首先找到該棋子的連通塊,然後統計連通塊外圍棋子的個數就是該棋子的氣。
找連通塊我也沒有用廣搜,用的是一種擴散的想法,程式碼類似於這樣子:往目標棋子滴一滴墨水,然後一秒鐘後就會往外擴散,然後下一秒往外擴散,直到擴散不了。 具體實現看程式碼。
程式碼:
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;
}