1. 程式人生 > >深信服2018校園招聘C++工程師程式設計題

深信服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_valmin_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 + 1str + 1是否匹配;
  • pattern[0]*,那麼判斷pattern + 1str + i(0<=i<strlen(str))裡面是否有一個匹配,只要有一個匹配,那麼就匹配了,如果所有的都不匹配,那麼就不匹配了;
  • pattern[0]為字母或數字,那麼就判斷str[0]pattern[0]是否相等,如果不相等就不匹配,如果相等,那麼還要判斷pattern + 1str + 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%的資料,不知道哪裡出了問題也不知道我是不是理解錯題目了,於是,我計算了下圍棋真正的氣

首先找到該棋子的連通塊,然後統計連通塊外圍棋子的個數就是該棋子的氣。

找連通塊我也沒有用廣搜,用的是一種擴散的想法,程式碼類似於這樣子:往目標棋子滴一滴墨水,然後一秒鐘後就會往外擴散,然後下一秒往外擴散,直到擴散不了。 具體實現看程式碼。

程式碼:

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;
}