# 字节跳动暑期后端实习面经(已offer)

## 一面

bool help(string s1, int i, string s2, int j, string target, int k, vector<vector<int>>& dp) {
if (k == target.size())
return true;
if (dp[i][j] != -1)
return dp[i][j];
bool res = false;
if (i < s1.size() && s1[i] == target[k]) {
res |= help(s1, i + 1, s2, j, target, k + 1);
if (res)
return dp[i][j] = res;
}
if (j < s2.size() && s2[j] == target[k])
res |= help(s1, i, s2, j + 1, target, k + 1);
return dp[i][j] = res;
}

bool isCross(string s1, string s2, string target) {
int l1 = s1.size(), l2 = s2.size(), l = target.size();
// s1和s2长度之和和target长度不相等
if (l1 + l2 != l)
return false;
// 记录中间状态结果，减少重复计算
vector<vector<int>> dp(l1 + 1, vector<int>(l2 + 1, -1));
dp[l1][l2] = 1;
return help(s1, 0, s2, 0, target, 0, dp);
}

## 二面

C++11 特性介绍；

template<class T>
void func(T* p) {}

linux网络指令，losf/netstat/tcpdump；

TCP/UDP，一揽子问题 + 应用场景；

vector<int> factors(int n) {
vector<int> res;
for (int i = 2; i * i <= n; ++i) {
if (n % i == 0) {
res.push_back(i);
res.push_back(n / i);
}
}
return res;
}

int minSteps(int src, int target) {
vector<int> dp(target + 1, INT_MAX);
dp[src] = 0;
// 从src开始遍历直达target
// 在当前数基础上加上每个因数，结果可以从当前位置再跳一步获得
for (int i = src; i < target; ++i) {
for (int factor : factors(i)) {
dp[i + factor] = min(dp[i] + 1, dp[i + factor]);
}
}
// 不可达
if (dp[target] == INT_MAX)
return -1;
return dp[target];
}

## 三面

1.随机链表复制，每个链表有一个随机指向的指针rand。直接照书上思路写的话比较麻烦，需要先复制每个节点插到原来节点后面，而后确定新节点指针指向，最后将新节点分离出来做成新的链表。

class Node{
public:
int val;
Node* next;
Node* rand;
Node(int v) : val(v), next(nullptr), rand(nullptr) {}
};

return nullptr;
map<Node*, Node*> m;
while (cur != nullptr) {
m[cur] = new Node(cur->val);
cur = cur->next;
}
while (cur != nullptr) {
m[cur]->next = m[cur->next];
m[cur]->rand = m[cur->rand];
cur = cur->next;
}
}

2.顺时针打印矩阵，借鉴左程云《程序员面试指南》上的写法，清晰易懂

// 每次打印矩阵一圈
void printCirc(vector<vector<int>>& matrix, int tr, int tc, int dr, int dc) {
int i = tr, j = tc;
while (j < dc) {
cout << matrix[tr][j] << " ";
++j;
}
while (i < dr) {
cout << matrix[i][dc] << " ";
++i;
}
while (j > tc) {
cout << matrix[dr][j] << " ";
--j;
}
while (i > tr) {
cout << matrix[i][tc] << " ";
--i;
}
}

void printMat(vector<vector<int>>& matrix) {
int tr = 0, tc = 0;    // 左上角行列坐标
int dr = matrix.size() - 1, dc = matrix[0].size() - 1;    // 右下角行列坐标
while (tr <= dr && tc <= dc) {
printCirc(matrix, tr++, tc++, dr--, dc--);
}
}

select/epoll/poll区别以及使用注意点；

100亿个访问某网站的用户id，统计出现次数最多的10个用户，老生常谈大数问题；

shell脚本写找出一个文件中出现次数最多的10个用户id，我把出现次数前10的次数显示了出来。。面试官看命令没啥问题就过了。

sort | uniq -c | awk 'print \$1' | sort -rn | head -10

03-23 322

05-07 314

03-07 2792

06-28 1360

01-13 7562

12-10 386

03-29 11万+

04-13 2189

03-26 881

05-15 1066

10-22 1181

05-14 30

01-15 1429

12-16 4599

03-31 3062

03-15 1万+

04-16 1820

06-19 183

03-28 266

03-08 2万+

#### 搜狗输入法也在挑战国人的智商！

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客