【每日刷题3.16】5道算法+15道面试 - 阿V

本文分享了一次面试经历,作者对4399公司产生了浓厚的兴趣,并讨论了在大厂工作与个人时间安排的权衡。文章中详细解析了几道算法题目,包括二叉树的右视图、回文字符串判断、进制转换、二进制中1的个数以及二进制比较。此外,还涉及了计算机科学概念如死锁的产生条件及其预防策略,进程状态,虚函数的作用和实现,函数重载与覆盖的区别,以及空类的组成。最后,文章以面试中关于内存对齐的讨论结束。
摘要由CSDN通过智能技术生成

心中思考了良久,昨天的面试经历,让我对4399充满了好感,之前是想进4399,但听师兄介绍,网易会更好,但如今对大厂了解的越多,就知道自己真正的需要是什么,我想在工作之余,晚上能有自己的时间去做自己的事情,而4399更适合我,我现在只有一个目标,进入4399!!!

算法题(牛客网)

1. 输出二叉树的右视图

昨天没写出来,今天再试试,难就难在创建二叉树,之前写过,现在又忘了哈哈哈。我靠着推导跟记忆写出来了!!!但是应该有更简单的方法。


代码详情:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 求二叉树的右视图
     * @param xianxu int整型vector 先序遍历
     * @param zhongxu int整型vector 中序遍历
     * @return int整型vector
     */
    vector<int> solve(vector<int>& xianxu, vector<int>& zhongxu) {
        // write code here
        TreeNode* root = create_tree(xianxu, zhongxu); //恢复二叉树
        
        queue<TreeNode*> que; //创建队列
        que.push(root);
        vector<int> result; //存储最终答案
        
        while(!que.empty()){
            int size = que.size(); //记录当前队列长度
            while(size--){
                TreeNode* node = que.front(); //记录队首节点
                que.pop(); //弹出队列
                if (size == 0){ //最后一个节点代表右视图观察节点
                    result.push_back(node->val);
                }
                if (node->left){ //压入左节点
                    que.push(node->left);
                }
                if (node->right){ //压入右节点
                    que.push(node->right);
                }
            }
        }
        
        return result;
    }
    
    
    //辅函数-恢复二叉树
    TreeNode* create_tree(vector<int> xianxu, vector<int> zhongxu){
        if (xianxu.size() == 0) return nullptr;
        int val = xianxu[0]; //当前根节点
        TreeNode* root = new TreeNode(val); //创建根节点
        auto pos = find(zhongxu.begin(),zhongxu.end(),val); //找到根节点在中序遍历的位置
        int length = pos - zhongxu.begin(); //计算目标节点到第一个节点的距离
        
        //链接左右节点
        root->left = create_tree(vector<int>(xianxu.begin()+1,xianxu.begin()+1+length),
                                 vector<int>(zhongxu.begin(),zhongxu.begin()+length));
        root->right = create_tree(vector<int>(xianxu.begin()+1+length,xianxu.end()),
                                 vector<int>(zhongxu.begin()+1+length,zhongxu.end()));
        return root; //返回根节点
    }
};

2.判断是否为回文字符串

 这道题简单,要是寻找最长回文子串就难了。


代码详情:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 
     * @param str string字符串 待判断的字符串
     * @return bool布尔型
     */
    bool judge(string str) {
        // write code here
        int l = 0,r = str.size()-1; //创建左右指针
        
        while(l < r){
            if(str[l++] != str[r--]){ //判断前后是否一样
                return false;
            }
        }
        
        return true;
    }
};

3. 进制转换

 笔试每次都考进制转换问题,这次好好刷一刷。这题让我理解了十进制转其他进制的方法。


代码详情:

class Solution {
public:
    /**
     * 进制转换
     * @param M int整型 给定整数
     * @param N int整型 转换到的进制
     * @return string字符串
     */
    string solve(int M, int N) {
        // write code here
        string t = "0123456789ABCDEF"; //转换字符串
        string ans; //存储最终答案
        bool minus = false; //存储M是否为正数
        
        if (M < 0){ //如果M为负数,记录minus,取正。
            minus = true;
            M = -M;
        }
        
        while(M){
            ans.push_back(t[M%N]); //取余
            M /= N;
        }
        
        if (minus) ans.push_back('-');
        reverse(ans.begin(), ans.end()); //反转字符串
        
        return ans;
    }
};

 4. 二进制中1的个数

我居然用二进制的正数负数原理,硬用数组写出来了。


代码详情:

class Solution {
public:
     int  NumberOf1(int n) {
         vector<int> ans; //存储二进制
         bool minus = false; //标志符,是否为负数
         
         if (n < 0){
            minus = true; //n为负数
            n = -n;
            ans = vector<int>(32,1); //由于负数要取反,因此这里直接取反
         } 
         else{
            ans = vector<int>(32,0);
         }
         
         int i = 0; //数组下标
         while(n){
             ans[i] = (ans[i] + (n % 2)) % 2; //取余
             i++;
             n /= 2;
         }
         
         reverse(ans.begin(), ans.end()); //翻转数组
         
         if(minus){
             int exp = 0; //记录进位
             ans[31] = (ans[31]+1) % 2;//负数加一
             if (ans[31] == 0) exp = 1;
             for(i = 30;i >= 0;--i){
                 if(exp == 1){ //向前进一
                     ans[i] = (ans[i] + exp) % 2;
                     exp = 0;
                     if (ans[i] == 0) exp = 1;
                 }
                 else{
                     break;
                 }
             }
         }
         
         int Num_1 = 0; //记录1的个数
         for(i = 0;i < 32;++i){
             if(ans[i] == 1) Num_1++;
         }
         
         return Num_1;
     }
};

但是有更加简单的版本,代码详情:

class Solution {
public:
     int  NumberOf1(int n) {
         int ans = 0; //记录1的个数
         int mark = 1;
         while(mark != 0){ //遍历二进制的1
             if (n & mark) ++ans;
             mark <<= 1;
         }
         
         return ans;
     }
};

5. 懂二进制

 有了上一题的经验,这一题利用上一题一位一位的看就行了。


代码详情:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param m int整型 
     * @param n int整型 
     * @return int整型
     */
    int countBitDiff(int m, int n) {
        // write code here
        int ans = 0; //记录有多少位不同
        int mark = 1; //用来获取单个位
        
        while(mark != 0){
            if ((m & mark) != (n & mark)){ //位数不同
                ++ans;
            }
            mark <<= 1; 
        }
        
        return ans;
    }
};

面试题

1. 什么是死锁?死锁产生的条件?

死锁:在两个或者多个并发进程中,如果每个进程持有某种资源而又等待其他进程释放它们保持的资源,从而导致进程无法继续进行,称为死锁。简单的来说,就是两个及以上进程无限期阻塞、相互等待的一种状态。

死锁产生的四个必要条件:

1. 互斥:至少有一个资源是非共享的。

2. 占有并等待:进程保持某种资源又同时申请其他资源(该资源被其他进程占有)。

3. 非抢占:进程不能被抢占,资源只能被进程主动释放。

4. 循环等待:若干个进程之间形成一种头尾相接的环形等待资源关系。

如何预防死锁:

1. 死锁预防(将四个必要条件至少一个条件打破,就能预防死锁):

a. 打破互斥条件:使资源共享。

b. 打破占有并等待:实行资源预先分配策略

c. 打破非抢占式条件:允许进程抢夺其他进程资源。

d. 打破循环等待条件:实现资源有序分配策略。

2. 死锁解除

1. 进程终止。

2. 资源抢占。

2. 进程有哪几种状态?

1. 就绪状态:等待分配处理

2. 运行状态:占用处理机资源运行。

3. 阻塞状态:等待某种资源或条件导致进程无法继续运行。

3. 虚函数的作用以及实现原理

 口头回答:虚函数是实现多态的基础,每个拥有虚函数的类都有一个虚函数表,该表保存每一个派生类的虚函数指针。

虚函数作用:定义一个基类指针,其指向一个继承类,可以通过基类指针在运行时决定调用基类函数还是继承类函数,从而实现多态。每个有虚函数的类都有虚函数表(占四字节),该类的任何对象都有虚函数的指针。

4. overload以及overwrite的区别

口头回答:重载是将函数重新定义,必须拥有不同的参数,相同的函数名,返回值可同可不同,覆写是将父类函数重新写,相同函数,相同参数,相同返回值。

重载(overload):子类改写父类方法,函数名必须相同,参数列表必须不同,返回值类型可以不同。

重写(overwrite):派生类重写基类函数,同一个函数的不同版本,相同的函数名,相同的参数列表,相同的返回值类型。

5. 一个空的class类里有什么

 口头回答:空的类里面有五个默认函数,默认构造函数,拷贝构造函数,析构函数,赋值运算符重载。

空的类含有(六个默认函数):默认构造函数,拷贝构造函数,析构函数,赋值运算符重载,取地址操作符重载,const修饰的取地址操作符重载。

6. 一个机构体中有一个int,一个char,一个static int,问这个结构体占多少内存?

  口头回答:int占4个字节,char占2个字节,static int占4个字节,根据字节对齐机制,该结构体占3*4 = 12字节。

内存对齐的原因:

1. 性能原因:未对齐地内存,处理器可能要做两次访问,而对齐的内存只需要一次访问。

2. 空间原因:防止空间浪费。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZW游戏制造

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值