【笔试练习】深信服校园招聘c/c 软件开发H卷

题目链接

一、填空题

  1. 如图所示,平面上有两条平行的线段,上面的线段有A0~A3 4个点,下面的线段有B0到B5 6个点,现在需要把所有的点都连接起来,有如下约束:

    每个端点,都至少有一条到另一平行线上端点的连线;

    连线之间不能有交叉(除了端点,线与线之间不能有连接的地方);

    请问,总共有多少种连法?

    答案:231

二、编程题

1. 访问权限

题目

JSON是一种可以用来保存配置的数据格式,其结构为树状。JSON中某个子节点的位置可以JSON路径的形式表示,JSON路径类似UNIX文件路径,以'/'分隔父子节点名。JSON路径中不会出现空格。

如下JSON值中
mem -- daemons -- findme
| |- waccd
|
|- apps -- appd

findme子节点的JSON路径为: /mem/daemons/findme

appd子节点的JSON路径为:/mem/apps/appd

waccd子节点的JSON路径为:/mem/daemons/waccd

有一个列表用来描述各JSON子节点是否允许用户编辑。如下:
Y /mem/daemons/findme
N /mem/daemons
Y /mem

如果有设置用户对某个子节点的权限,则实际权限为该设定权限,否则继承其父节点的可访问性,对根节点的默认访问权限为N。
输入描述

第一行为一个正整数N,表示接下来有N行数据(0 < N < 100)

第2行到第N+1行,为字符串Path,表示待检查访问权限的JSON路径。

第N+2行为一个正整数T,表示接下来有T行数据(0 < T < 1000)

接下来会有T行数据,格式为"权限 JSON路径"。

权限有两种取值:Y和N

JSON路径最大长度为256
输出描述

输出"权限",权限表示该节点的实际访问权限。
示例1

输入例子:
1
/mem/total
3
Y /mem/daemons/findme
N /mem/daemons
Y /mem

输出例子:
Y

思路------前缀树

将字符串 /mem/start拆分成 mem、start 两单词, 每个单词为一个前缀。

  • 前缀树的属性

    • 当前文件夹是否有权限
    • 当前文件夹是否是继承父目录的权限
    • 当前文件夹的子目录
    • 当前文件夹的名字
  • 前缀树的操作

    • 插入
    • 查询
    • 更新所有文件夹的权限信息
  • 主程序读入所有信息

    • 将待查询的信息,先存在一个 vector 中
    • 将其余信息用于构建前缀树
  • 构建前缀树的过程

    • vector<string> str 保存路径的名字信息(利用函数拆分字符串)
    • 检查map中是否有 str[i] 这个文件夹的名字, 如果没有, 则创建一个文件夹 ,并赋予父目录的权限
    • node 指向 map[str[i]] 这个节点
  • 查询前缀树的过程:

    • 逐个判断path 中的名字是否在前缀树出现
    • 如果没有出现,则返回当前 node 的权限

代码:

cpp 复制代码
#include<iostream>
#include<vector>
#include<map>
#include<unordered_map>
using namespace std;

class Trie {
public:
    bool hava_Authority = false; 
    bool isInherient = true; // 当前节点的权限是不是继承父节点的
    unordered_map<string, Trie*> ls; // 孩子节点
    string name;
    Trie(bool au, string str) {
        hava_Authority = au; 
        name = str;
    }
    Trie() {}
    void insert(bool au, vector<string> str) {
        if (str.empty()) { 
            this->isInherient = false;
            this->hava_Authority = true;
            return;
        }
        Trie* node = this; // 当前节点(作为父节点)
        for (int i = 0; i < str.size(); i++) {
            // 在当前节点的孩子没有找到,说明目前没有该路径,需要新建节点
            if (node->ls.find(str[i]) == node->ls.end()) {
                Trie* tmp = new Trie(node->hava_Authority, str[i]); // 继承父节点的权限
                node->ls.insert(make_pair(str[i], tmp)); // umap 的插入语句
            }
            // 已经存在该路径,更新当前节点的下一个访问位置
            node = node->ls.find(str[i])->second;
        }
        // 遍历完 str,就可以更新最后一个节点的权限
        if (node->isInherient) node->hava_Authority = au; // 记录新的权限
        node->isInherient = false; // 由于最后一个节点肯定有自己的权限,所以标记为非继承
    }

    bool query(vector<string> str) {
        Trie* node = this;
        for (int i = 0; i < str.size(); i++) {
            // 如果在下一层找不到,说明当前层就是最终层
            if (node->ls.find(str[i]) == node->ls.end()) {
                break;
            }
            // 如果在孩子节点能找到下一层,就递归查询
            node = node->ls.find(str[i])->second;
        }
        // 返回当前层的权限
        return node->hava_Authority;
    }

    // 权限更新
    void update() {
        Trie* node = this;
        for (auto it = node->ls.begin(); it != node->ls.end(); it++) {
            if (it->second->isInherient) { // 是继承,此时权限是父节点的权限
                node->ls[it->first]->hava_Authority = node->hava_Authority;
            }
            node->ls[it->first]->update(); // 递归更新儿子
        }
    }
};

vector<string> split(string str) {
    str += "/"; // 在末尾加上 '/' ,遇到最后一个字符也不需要特殊处理
    str = str.substr(1); // 跳过第一个 '/' 开始遍历
    vector<string> res;
    string tmp;
    for (int i = 0; i < str.size(); i++) {
        if (str[i] == '/') {
            if (tmp.size()) res.push_back(tmp);
            continue;
        }
        tmp += str[i];
    }
    return res;
}

int main() {
    Trie* root = new Trie();
    int n;
    cin >> n;
    vector<vector<string>> query;
    while (n--) {
        string t;
        cin >> t;
        query.push_back(split(t));
    }
    cin >> n;
    string a, b;
    while (n--) {
        cin >> a >> b;
        if (a == "Y") {
            root->insert(true, split(b));
        }
        else {
            root->insert(false, split(b));
        }
    }
    // 插入结束后,对所有节点进行权限更新
    root->update();
    // 查询权限
    for (int i = 0; i < query.size(); i++) {
        if (root->query(query[i])) {
            cout << "Y\n";
        }
        else {
            cout << "N\n";
        }
    }
    return 0;
}
相关推荐
未知陨落10 分钟前
数据结构——二叉搜索树
开发语言·数据结构·c++·二叉搜索树
大波V510 分钟前
设计模式-参考的雷丰阳老师直播课
java·开发语言·设计模式
无敌最俊朗@24 分钟前
unity3d————接口基础知识点
开发语言·c#
一丝晨光1 小时前
gcc 1.c和g++ 1.c编译阶段有什么区别?如何知道g++编译默认会定义_GNU_SOURCE?
c语言·开发语言·c++·gnu·clang·gcc·g++
南城花随雪。1 小时前
Spring框架之装饰者模式 (Decorator Pattern)
java·开发语言·装饰器模式
究极无敌暴龙战神X1 小时前
前端学习之ES6+
开发语言·javascript·ecmascript
虞书欣的61 小时前
Python小游戏24——小恐龙躲避游戏
开发语言·python·游戏·小程序·pygame
FHYAAAX1 小时前
【机器学习】任务十:从函数分析到机器学习应用与BP神经网络
开发语言·python
汉克老师2 小时前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
爱吃生蚝的于勒2 小时前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计