腾讯 pc客户端 一面

1. git 工具的 rebase merge 的区别

git rebase主要用于将一个分支的修改重新应用到另一个分支上,它能创建更线性的项目历史;而git merge则是将两个分支的历史合并成一条,可能会产生新的合并提交,保留了原始分支的历史。简而言之,rebase 重写历史以线性顺序展示,merge 保留了分支的并行历史。


2. 如果有一个错误的提交,如何把它回退到正确的,包括本地远端,都回退

要回退一个错误的提交,可以在本地使用git revert <commit_hash>创建一个新提交来撤销错误提交的改变,然后用git push推送到远端。如果需要彻底从历史中移除,可以使用git reset --hard <commit_hash>回退到正确的提交状态,然后强制推送到远程git push --force。


3. 虚函数和纯虚函数的区别

虚函数是一个可以在派生类中被重写的成员函数,它允许多态行为。一个纯虚函数则是在基类中声明但没有给出定义的虚函数,用= 0语法表示。一个包含纯虚函数的类是抽象类,不能实例化,而是要求派生类提供纯虚函数的实现。简单来说,虚函数允许被覆盖,纯虚函数必须被覆盖。


4. 构造函数和析构函数的作用,对类的成员变量的初始化,放在类内和类开头类外有什么区别

构造函数的作用是初始化类的对象。当一个对象被创建时,构造函数会被调用来为成员变量赋初始值,并执行任何必要的设置或分配资源的操作。

析构函数则是在对象生命周期结束时被调用,用于执行清理工作,如释放分配的资源,它帮助防止资源泄露。

对于类的成员变量初始化,如果在类内部进行初始化,那么提供的是默认值,适用于所有未明确覆盖这些默认值的对象。如果在类的构造函数初始化列表中初始化,这是针对特定对象的初始化操作,可以基于构造函数接收的参数来设置成员变量的值。

初始化列表比在构造函数体内部赋值更有效,因为它可以直接构造成员变量,而不是先构造然后赋值,这对于对象成员和const或引用成员尤其重要,因为它们必须在初始化列表中初始化。


5. 有没有有到过opencv库底部出错的现象

OpenCV库底部出错的现象原因可能包括:

  1. API使用不当:比如错误的参数、不恰当的资源管理。
  2. 兼容性问题:库版本和依赖的操作系统或其他库版本不兼容。
  3. 资源限制:如内存不足,导致无法正常加载或处理数据。
  4. 内部库的bug:即使是广泛使用的库,也可能存在尚未修复的错误。
  5. 不支持的操作:尝试执行库不支持的功能或操作。


6. 栈区和堆区的区别

栈区(Stack)是由操作系统自动管理、分配释放的内存区域,主要用于存放函数的局部变量、函数参数和函数调用的相关信息。栈上分配的内存有自动的作用域,当函数调用结束时,这部分内存会自动释放。

堆区(Heap)是程序员通过代码申请分配释放的内存区域,主要用于动态内存分配。堆上分配的内存生命周期由程序员控制,如果不及时释放,可能会导致内存泄漏。堆的使用相对灵活,可以动态地分配大块内存。


7. 内存泄漏的话,如何调试解决

内存泄漏的调试解决可以通过以下步骤:

  1. 代码审查:检查代码中是否有未配对的内存分配和释放。
  2. 使用调试工具:如 Valgrind、Leaks(macOS)、Visual Leak Detector(Windows)来检测运行时内存使用情况。
  3. 分析堆栈跟踪:定位分配内存时的函数调用堆栈,了解哪些分配未被释放。
  4. 检查第三方库:确认是否有来自外部库的内存泄漏。


8. 有没有使用互斥锁,遇到死锁的问题,如何解决一个线程长时间占用资源,另外一个占用不到的情况

死锁形成的四个必要条件包括:

  1. 互斥条件:资源同时只能由一个线程占用。
  2. 持有并等待:线程已持有资源,在等待获取其他资源时不释放已持有资源。
  3. 不可抢占:资源不能被强制从占有线程中取走,只能由持有线程主动释放。
  4. 循环等待:存在一组等待过程,其中每个线程持有的资源被下一个线程所请求。

针对一个线程长时间占用资源的问题,可以考虑:

  • 确保占用锁的线程在完成其需要的操作后尽快释放锁。
  • 使用条件变量或者信号来合理调度线程,防止某个线程长时间占用资源。
  • 对长时间执行的任务进行拆分,减少单次锁定时间,为其他线程释放机会。


手撕代码:

第k大的数组元素,如何降低时间复杂度

要找到数组中第k大的元素,一种高效的方法是使用快速选择算法(QuickSelect)。快速选择算法是快速排序算法的变种,用于在未完全排序的情况下找到第k大(或第k小)的元素。它的平均时间复杂度是O(n),最坏情况下的时间复杂度为O(n^2),但与快速排序相比,它只需要对数组的一部分进行排序,可以显著减少计算时间。

示例:

#include <vector>
using namespace std;

int partition(vector<int>& nums, int left, int right) {
    int pivot = nums[left];
    int l = left + 1;
    int r = right;
    while (l <= r) {
        if (nums[l] < pivot && nums[r] > pivot) {
            swap(nums[l++], nums[r--]);
        }
        if (nums[l] >= pivot) l++;
        if (nums[r] <= pivot) r--;
    }
    swap(nums[left], nums[r]);
    return r;
}

int quickSelect(vector<int>& nums, int left, int right, int k) {
    if (left == right) return nums[left];
    int pivotIndex = partition(nums, left, right);
    // 第k大,转换为第 len-k 小的问题。
    if (k == pivotIndex) return nums[k];
    else if (k < pivotIndex) return quickSelect(nums, left, pivotIndex - 1, k);
    else return quickSelect(nums, pivotIndex + 1, right, k);
}

int findKthLargest(vector<int>& nums, int k) {
    int n = nums.size();
    // 第k大的数在倒序排列的位置为 n-k
    return quickSelect(nums, 0, n - 1, n - k);
}

顺便给大家分享一下,民族企业大厂前后端测试(https://jsj.top/f/o38ijj)捞人,待遇给的还不错,感兴趣的可以来试试!