0818-0824面试题目和复习整理

发布于:2024-08-26 ⋅ 阅读:(137) ⋅ 点赞:(0)

根据面试问的问题整理一下

1. 并查集

int n = 1005; // n根据题目中节点数量而定,一般比节点数量大一点就好
vector<int> father = vector<int> (n, 0); // C++里的一种数组结构

// 并查集初始化
void init() {
    for (int i = 0; i < n; ++i) {
        father[i] = i;
    }
}
// 并查集里寻根的过程
int find(int u) {
    return u == father[u] ? u : father[u] = find(father[u]); // 路径压缩
}

// 判断 u 和 v是否找到同一个根
bool isSame(int u, int v) {
    u = find(u);
    v = find(v);
    return u == v;
}

// 将v->u 这条边加入并查集
void join(int u, int v) {
    u = find(u); // 寻找u的根
    v = find(v); // 寻找v的根
    if (u == v) return ; // 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
    father[v] = u;
}

2. 梯度下降法和二分法求一个函数

对于梯度下降法,x应该考虑实际函数来做,而且lr不能设置的太大,会跳过这个解,二分法最好还是用while来写吧,我用的递归,很奇怪

#include <iostream>
#include <vector>
#include <math.h>
using namespace std;
int m = 10000;

float e = 0.0001;
float f(float x) {
    return exp(x) + pow(x, 3) - 5;
}
float grad(float x) {
    return exp(x) + 3 * x * x;
}
float func1(float left, float right) {
    float mid = (left + right) / 2;
    if (f(mid) > e) {
        return func1(mid, right);
    }
    else if (f(mid) < -e) {
        return func1(left, mid);
    }
    else return mid;
}
float func2(float x) {
    int epoch = 10000;

    float step = 0.0001;
    for (int i = 0; i < epoch; i++) {
        if (f(x) > -e && f(x) < e) {
            return x;
        }
        
        x = x - step * grad(x);
        cout << x << endl;
    }
    return x;
}
int main()
{
    float x = 3;
    cout << func1(-10,10) << endl;
    return 0;
}

3. 为什么分类模型用交叉熵损失函数,而不用MSE

1. MSE是均方误差损失函数,表示的是m个样本的均值,网络模型用它来预测,就是为了拟合实际的值与预测值之间的差。得到的是一个值。

2. 分类问题一般是需要一系列的激活函数,将预测值映射到0-1之间

3. 分类问题使用交叉熵,Loss下降的更快。

4. 使用交叉熵是凸优化,MSE是非凸优化

4. maxpooling的反向传播

5. scaled product attention

6. 链表逆序

我怎么都想不出来链表逆序,烦死了

看模板思路吧: 是我想的太复杂了,绕来绕去 其实每次只要维护三个节点,把从左到右的连接改成从右到左的就行了,然后三个节点都往后移动一次。

    ListNode * reverse(ListNode * node){
        ListNode * pre = nullptr, * cur = node;
        
        while(cur!=nullptr){
            ListNode * nextt = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nextt;
        }
        return pre;
    }

7. K个一组反转链表

    ListNode * reverse(ListNode * node){
        ListNode * pre = nullptr, * cur = node;
        
        while(cur!=nullptr){
            ListNode * nextt = cur->next;
            cur->next = pre;
            pre = cur;
            cur = nextt;
        }
        return pre;
    }
    ListNode * findtail(ListNode * node){
        while(node != nullptr && node->next != nullptr){
            node = node->next;
        }
        return node;
    }
    ListNode* reverseKGroup(ListNode* head, int k) {
       if(k == 1) return head;
        vector<ListNode *> heads;
        ListNode * cur = head;
        heads.push_back(head);
        int idx = 1;
        while(cur != nullptr){
            if(idx % k == 0){
                ListNode * t = cur->next;
                heads.push_back(t);
                cur -> next = nullptr;
                cur = t;
                
            }else{
                cur = cur ->next;
            }
            idx++;
        }
        for(auto head:heads){
            while(head!=nullptr){
                cout<<head->val<<" ";
                head = head->next;
            }cout<<endl;
        }
        // 翻转链表
        ListNode * res = new ListNode(0);
        ListNode * pre = res;
        if((idx-1)%k == 0){
            for(ListNode* node : heads){
                node = reverse(node);
                ListNode * tail = findtail(node);
                pre -> next = node;
                pre = tail;
            }
        }else{
            for(int i =0;i<heads.size()-1;i++){
                ListNode * node = reverse(heads[i]);
                ListNode * tail = findtail(node);
                pre -> next = node;
                pre = tail;
            }
            pre->next = heads[heads.size()-1];
        }
        return res->next;
    }

思路倒是不难想,就是先分组再逆序再组合起来,但是好麻烦好容易出错。。

合起来的时候要知道每个子链表的头尾,我是根据头找尾,但是应该可以在reverse的时候就把尾记录下来,这样可以直接得到头尾

还有,每次通过while(x->next  != nullptr)的时候要加上while(x!=nullptr && x->next != nullptr)

8. python写AUC

def calculate_AUC(y_pred,y_true):
    sorted_indices = np.argsort(y_pred)
    sorted_y_true = y_true[sorted_indices]
    sorted_y_pred = y_pred[sorted_indices]

    # 计算真阳性率和假阳性率
    tpr = []  # 真阳性率
    fpr = []  # 假阳性率
    total_positive = np.sum(sorted_y_true)
    total_negative = len(sorted_y_true) - total_positive

    current_positive = 0
    current_negative = 0
    for i in range(len(sorted_y_true)):
        if sorted_y_true[i] == 1:
            current_positive += 1
        else:
            current_negative += 1
        tpr.append(current_positive / total_positive)
        fpr.append(current_negative / total_negative)

    # 计算AUC
    auc = np.trapz(tpr, fpr)
    return auc

记得排序并根据排序返回索引的方式:np.argsort()

记得求积分的方法:np.trapz()

AUC的时间复杂度?

9. 全排列公式

关键在于去重,去重之前我都会写,唉,还是要记一下思路

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        // 此时说明找到了一组
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            // used[i - 1] == true,说明同一树枝nums[i - 1]使用过
            // used[i - 1] == false,说明同一树层nums[i - 1]使用过
            // 如果同一树层nums[i - 1]使用过则直接跳过
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            if (used[i] == false) {
                used[i] = true;
                path.push_back(nums[i]);
                backtracking(nums, used);
                path.pop_back();
                used[i] = false;
            }
        }
    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        result.clear();
        path.clear();
        sort(nums.begin(), nums.end()); // 排序
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};

全排列的时间复杂度是多少?

10. FM的公式,如何优化的

用pytorch写:

import numpy as np
import torch.nn as nn
import torch
class FM(nn.Module):
    def __init__(self,input_size,k):
        super(FM, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.v = nn.Parameter(torch.randn(input_size,k))

    def forward(self,x):
        linear_part = self.linear(x)
        interaction_part = 0.5 * torch.sum(torch.pow(x@(self.v),2) - pow(x,2)@pow(self.v,2))
        return linear_part + interaction_part

11. 颜色分类

数组只包含0,1,2三种,排序

这题其实感觉在多分类里能用到,比如0101001这种排序成0001,方便求AUC

没想到这么简单的做法,我一直在纠结怎么交换,结果一个ptr就能解决

    void sortColors(vector<int>& nums) {
        // 对0排序
        int ptr = 0;
        int n = nums.size();
        for(int i =0;i<n;i++){
            if(nums[i] == 0){
                swap(nums[ptr],nums[i]);
                ptr++;
            }
        }
        for(int i =0;i<n;i++){
            if(nums[i] == 1){
                swap(nums[ptr],nums[i]);
                ptr++;
            }
        }
    }

12. 分割回文串

只要知道这道题是回溯就行了,和全排列一样的思路

    bool huiwen(string s){
        int i = 0, j = s.size()-1;
        while(i<j){
            if(s[i] != s[j]) return false;
            i++, j--;
        }
        return true;
    }
    vector<vector<string>> res;
    vector<string> tmp;
    void dfs(int begin,string s){
        if(begin == s.size()){
            res.push_back(tmp);
        }
        for(int i = begin;i<= s.size()-1;i++){
            if(huiwen(s.substr(begin,i-begin+1)))
            {
                tmp.push_back(s.substr(begin,i-begin+1));
                dfs(i+1,s);
                tmp.erase(tmp.end()-1);
            }
        }
    }
    vector<vector<string>> partition(string s) {
        dfs(0,s);
        return res;
    }

11.MMOE是如何对多目标进行预估的,如果单独把两个模型直接预测得到目标,和用多目标模型有什么区别?

12. c++怎么处理异常

13. 给数组a1,a2,a3,b1,b2,b3 怎么不使用额外空间变成a1,b1,a2,b2,a3,b3

14.CT值表示什么意义,范围是多少,CT值为0代表什么

15. 双向链表和数组的插入\访问时间复杂度,双向链表如何插入一个数

16 pytorch如何反向传播,如果一个层被冻结了,上一层的梯度如何传播?

17. tensorRT是如何部署,加载模型并预测的?

18. 我的去噪模型的精度是如何衡量的,用什么指标,有什么其他指标,他们分别有什么缺陷

19. 联想编程题:

给一个字符串,里面是0-9之间的数字。对字符串进行任意分割,看每个子串(连续的)是否能被4整除,输出所有能整除的子串的个数。(前导0也算,04和4算两个)

我只会用for套for,只过了45%,感觉dp能做,但是没写出来