2022-03-03 SmartX

提问环节

项目

Q1:具体调了那些参数?
Q2:具体的IO是什么?对于不同客户,IO是不一样的,是怎么处理的呢?
Q3:根据我的经验,实际的现场IO是很复杂的,不是某个单一的IO,你们是怎么考虑的呢?
Q4:能谈谈你实际过程中,对哪个具体参数的调整经验吗?

个人感受:可能面试官本身就是做存储的,所以项目问的很细,直击痛点,怼了四十分钟。。。

基础

Q1: 下面代码输出什么?

class A {
  public:
    virtual int get_v() {return v;}

  private:
    int v = 10;
};

int main() {
    A* a = new A();
    memset(a, 0, sizeof(A));
    std:: cout << a->get_v() << std::endl;
    delete a;
}; 

答案:虚函数的调用,都是通过对象的ptr(指向虚函数表,虚函数表存在只读数据段.rodata,也就是常量区;虚函数位于代码段.text,也就是代码区)指针,所以memset会也会将这个ptr指针初始化为0,导致后面的调用出错。所以,memset函数一般用来初始化基本数据类型的数组,类中含有C++类型的对象(string, list, set, map等)时,千万不要使用memset进行初始化,因为会破坏对象的内存,可用构造函数来实现。类中含有虚函数,也不能用memset,会报错

参考博文

Q2:下面代码执行后,v的值是多少?

void f(uint16_t* addr) { (*addr) = 10; }
uint32_t v; f(&v); 

答案:会报错,&v是(uint32_t * )类型,addr 是 (uint16_t * )类型。除非强制类型转化,附上测试代码

#include <bits/stdc++.h>
using namespace std;

class A {
  public:
    virtual int get_v() {return v;}

  private:
    int v = 10;
};

void f(uint16_t* addr) { 
    (*addr) = 10; 
}

 

int main() {
    // T1
    // A* a = new A();
    // memset(a, 0, sizeof(A));
    // cout << a -> get_v() << endl;            // 报错
    // delete a;
    // T2
    uint32_t v = 0; 
    
    // uint16_t* p = &v;       // 报错
    // uint16_t* p = (uint16_t*)&v;       // 强制转化
    // *(p) = 10;
    // cout << (*p) << endl;          // 输出10

    // f(&v);           // 报错
    f((uint16_t*)&v);           // 强制类型转化
    cout <<  v << endl;           // 输出10
    return 0;
}; 

Q3:

  • 平时写题、比赛时会用到树结构吗?
    • 会,会用二叉树,但是我们一般不用链表实现,而是用数组模拟,例如父节点存在下标为 x 的位置,那么它的左右孩子分别为 (2 * x) 和 (2 * x + 1),这样虽然会造成内存使用不充分,但是操作起来,比链表方便
  • 那如果需要对树进行增加、删除节点呢
    • 我们一般用STL容器的 set map,它们的底层都是树结构,一般都可以满足我们的需求
  • 那你们由考虑STL容器效率吗,有没有效率不够的时候,举个例子呢?
    • 额,一般不会,没怎么遇到过。。。。

Coding

Q:在不开O(n)空间的前提下,实现如下转换:abbceddddaaaaaaaaaaaakaa -> ab2ced4a12ka2

A:

#include <bits/stdc++.h>
using namespace std;

class Solution {
public:
    void convert(string& s, int& slow, int cnt) {
        vector<char> v;
        while (cnt) {
            int tmp = cnt % 10;
            v.push_back(tmp);
            cnt /= 10;
        }
        for (int i = v.size() - 1; i >= 0; --i) {
            s[slow++] = char(v[i] + '0');
        }
    }

    void solve(string& s) {
        int fast = 0, slow = 0;     // fast 为旧字符串的遍历位置, slow 为新字符串的当前更新位置
        int cnt = 0;                // 记录重复数字个数
        for (fast = 0; fast < s.size(); ++fast) {
            if (fast > 0 && s[fast] != s[fast - 1]) {
                s[slow++] = s[fast - 1];
                // !!!注意坑 不能直接 s[slow++] = char(cnt + '0'), cnt 可能大于9
                if (cnt > 1) {     // 重复字符
                    convert(s, slow, cnt);
                }
                cnt = 1;
            } else {
                cnt++;
            }
        }
        // 尾部处理
        // !!对于 for 处理,最后一定得考虑尾部处理!!!
        // 面试时,调试了半天。。。
        s[slow++] = s[fast - 1];
        if (cnt > 1) {     // 重复字符
            convert(s, slow, cnt);
        }
        // 删除多余字符
        s.erase(slow, s.size());
    }
};


int main() {
    Solution solution;
    string s = "abbceddddaaaaaaaaaaaakaa";
    solution.solve(s);
    cout << s << endl;
    return 0;
}

提问

Q:对于网上一些用C/C++实现一个数据库、聊天室这样的项目,您们看到是怎样的感受?对实际工作有帮助吗?

A:如果你深入跟进去了,对涉及到的相关知识去进一步学习,那么肯定是有作用的,但是如果只是过一遍,其实效果不大,与实际工作差别挺大的。

面试官评价

你的项目,其实还是浮在上面,对参数去调参,但是没有对参数到底如何影响性能的,做进一步了解,算一般吧。

基础方面,不是很差,也不是很好,中等水平。

你的Coding还是很不错的,无论是思路,还是调试的敏捷程度,都是很不错的,但是对比工程上的代码,有些地方还是比较粗糙的。当然了,我们对应届生的要求,不能和社招相同。整体我这边会给你通过的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容