彼が合格したと思いますか
片側2020/12/20/14:00-14:50
1.はじめに(2分)
2. redisソースコードを読んだ後、一般的に使用されるデータ構造について話します。
文字列、ジャンプリスト、辞書、圧縮リスト、リンクリスト
3.ジャンプテーブルを紹介します。
初期化時にヘッダーを割り当てます。また、リンクリストのようにテーブルにリンクします。各ノードにランダムにレイヤーを割り当て、その先頭から各レイヤーを各ノードに接続します。数値が大きいほどそのレイヤーのうち、それは背面に直接接続され、トラバースが同じであることを含めて、トラバースをスキップできるように、高から低までどの番号を見つけるかを含めて、下の中間レイヤーは接続されません。
4.検索の時間計算量はどれくらいですか:log(n)
5.リンクリストと比較した場合のスペース占有率は?主な理由は、余分なレイヤーがあることです。各ノードのレイヤー数が異なります。レイヤーがすべて1の場合、リンクリストに縮退します。
6.ベクトルpush_back拡張:2倍の拡張、実際にはもっと複雑になる可能性があります
7.拡張後、そのメモリアドレスは変更されますか:変更されます。以前は、元の要素を再度コピーし、新しいスペースを作成し、過去をコピーしてから、前のスペースを解放していました。しかし今、それは移動セマンティック移動を介してです
8.移動のセマンティクスについて話します。前のコピーと比較して、要素は1回コピーされ、次に前のコピーが破棄されます。現在の移動は、直接移動することと同じです。つまり、ライフサイクルを延長し、新しいポインタを元の位置に移動してから、元のポインタをnullに割り当てるという言い方を別の言い方で考えたいと思います。
9. moveの最下位の実装:ええと、static_castが表示されますが、詳細を完全には理解していません。
10.右辺値の参照:一時変数、または消滅しようとしている変数は、デッド値と呼ばれ、そのライフサイクルが延長されて左辺値になります。
11.いつリリースされるか:私の理解では、それは左辺値(左辺値と同じ意味)と同等です
12.ベクターに保存されているデータのすべてのメモリスペースを解放する方法:最初にサイズ変更を言ってから、別の関数に変更しました。名前を覚えていません。
13.仮想関数について話します。サブクラスは親クラスの関数を書き換えます。
14.詳しく説明する例を挙げましょう。たとえば、動物(親)は食べますが、他のサブカテゴリでは食べ方が異なります。このとき、この関数には仮想関数を使用してください。
15.仮想関数と関数書き換えの違いは何ですか:(私はそれを混乱して推測しました)私はそれをこのように推測しました
16.具体的に教えてください:しかし、そのように推測するかどうかはわかりません。
17.質問を変更して、参照とポインタについて話しましょう:1。メモリ使用量; 2。初期化; 3。ポインティングは変更可能
18.他に何がありますか:これ以上
19.参照を破棄できますか:わかりません
20.スマートポインターについて学びましたか?それを実装する方法を教えてください:参照カウントが追加されました
21.具体的には、異なるスマートポインターが同じオブジェクトを指します。指すポインターがある場合、その参照カウントは+1であり、最終的に0になると、自動的に破棄されます。
22.スマートポインターは複数のスレッドで使用できますか:異なるスレッドのスマートポインターは同じオブジェクトを指しますか?はい:適用できるはずだと思います
23.わかりませんよね?確かに当てはまります。どう思いますか?異なるスレッドがリソースを共有しているため、同じオブジェクトを参照できます。
24.読み取りと書き込みの競合はありますか:はい
25.解決方法:ロックして解決する必要があります
手裂け
1.インオーダートラバーサル(反復)
给定二叉树的,构造一个中序遍历的迭代器,对应的功能是返回二叉树上的下一个元素。
class Iterator {
public:
TreeNode* next();
}
1.1アイデアの話し合い(約6分)
私:実装の過程で、順序どおりのトラバーサルを記録する必要があります。
顔:
より具体的に教えてください。私:たとえば、初期化するときに、順序どおりのトラバーサルをベクトルに直接格納して、次を使用します。直接アクセスするには。
面:長所と短所について教えてください。
私:長所は、次に呼び出すときに複雑さがO(1)であるということです。短所は、初期化中に完全にトラバースする必要があることです。スペースの複雑さはOです。 (n)
:他の方法を試すことができます。I
:余分なスペースは必要
ありません。表面:いいえ。ただし、O(logn)などのO(n)よりも小さいです。
私:ああ、それはスタックを使用することです、それをバラバラに記録します...
顔:それから書き始めます
顔:最初にTreeNode
を定義しますI:ツリーを定義する必要があります
顔:これは
必要ありません。私:これを実行する必要があります。
顔:まだ必要ありません
1.2途中のコード記述(約8分)
Surface:ルートノードはコンストラクターから渡されます
#include <iostream>
#include <stack>
using namespace std;
struct TreeNode {
int val;
TreeNode* left, *right;
};
class Iterator {
public:
stack<TreeNode*> s;
Iterator(TreeNode* root) {
// s.push(root);
TreeNode* t = root;
while (t) {
s.push(t);
t = root->left;
}
}
TreeNode* next() {
if (s.empty()) return nullptr; // 面试官后面提醒
TreeNode* ret = s.top();
TreeNode* t = ret;
if (t&&t->right) {
t = t->right;
while (t) {
s.push(t);
t = t->left;
}
} else {
TreeNode* tRight = t;
s.pop();
if (s.empty()) return ret; // 面试官后面提醒
t = s.top();
while (t->right == tRight) {
s.pop();
if (s.empty()) return ret; // 面试官后面提醒
tRight = t;
t = s.top();
}
}
return ret;
}
}
1.3コードの説明(4分)
書いた後、コードを説明し、特別な状況が追加されていないいくつかの場所を指摘します。
2.フルアレンジ
给定一个数组,打印它的全排列
[1,2]
-> [1,2] [2,1]
2.1アイデアについて話す(2分)
- ニアン:はっきりしていません。大丈夫だと思ったら書いてください
2.2コード(7分)
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> ans;
void sol(vector<int>& v, vector<int> ret, vector<bool> flag) {
if (ret.size() == v.size()) ans.push_back(ret);
for (int i = 0; i < v.size(); ++ i) {
if (flag[i]) {
ret.push_back(v[i]);
flag[i] = false;
sol(v, ret, flag);
flag[i] = true;
ret.pop_back();
}
}
}
int main() {
vector<int> v;
for (int i = 1; i <= 3; ++ i)
v.push_back(i);
vector<int> ret;
vector<bool> flag(v.size(), true);
sol(v, ret, flag);
for (int i = 0; i < ans.size(); ++ i) {
for (int j = 0; j < ans[i].size(); ++ j)
cout << ans[i][j] << ' ';
cout << endl;
}
}
修辞的な質問
- 私:何を強化する必要があると思いますか?
- 表面:幅は問題ありませんが、仮想関数やスマートポインターなどの深さは十分ではありません
両面2020/12/21/14:05-15:05
自己紹介
C ++は履歴書に書かれていますが、他の言語を受け入れますか:どの言語ですか?
golang、python:許容できますが、c ++を優先します
インターンシップ時間:他に問題はありません、あなたは定期的になるためにインターンすることができます
正規化の時期を説明してください(時間がかかることを忘れないでください):特別な事情はありません。インターンシップが定期的に行われることを願っています。
ベース上海?:はい
インターンシップの仕事を説明する(3分)
プロセス、スレッド、およびコルーチンについて説明します。プロセスはリソーススケジューリングユニットであり、スレッドはcpuスケジューリングユニットであり、コルーチンにはデータを送信するためのチャネルがあります。粒度:プロセス>スレッド>コルーチン
それらの長所と短所について話してみることができます。プロセス切り替えの短所、時間のオーバーヘッド。他の人を知らないかもしれないので、それについて話しましょう。
プロセスとスレッド間の通信について話します。プロセス:チャネル(誤って、パイプはチャネルと呼ばれます...)、シグナル、ソケットも、スレッドはより多くのシグナルを使用します。
アルゴリズムの質問
lru、キャッシュサイズはK、データ構造の設計方法について説明します。リンクリストを使用してキャッシュデータを保存し、アクセスプロセスについて説明します。引き続き、リンクリストルックアップの欠点について説明します。時間の複雑さは次のとおりです。 O(n)なので、ハッシュを使用して検索します。時間計算量をO(1)に減らすことができます。(2分)
有効期限を追加する場合:リンクリストノードに更新時間を追加し、データにアクセスするときに、期限が切れているかどうかを判断します。(3分)
書いてください:
(最初は自分で実装したリストを書いていましたが、とても面倒でした。以前にstlを使っていたことに突然気づきました。この時は15分経ちました。)私:代わりにstlを使ってもいいですか。。。。
顔:はい、変更できます
(15分後に終了します)
#include <iostream>
#include <unordered_map>
#include <list>
#include <pair>
using namespace std;
struct ListNode {
int val;
ListNode* next, *pri;
double update;
};
class lru {
// ListNode* head, *tail;
list<pair<int, double>> l;
unordered_map<int, list<pair<int, double>>::iterator > m;
int K;
int nums;
double T;
lru(int k, double t) {
K = k;
nums = 0;
T = t;
}
void set(int x) {
if (m.find(x) == m.end()) {
auto p = make_pair(x, time());
l.push_back(p);
m[x] = l.rbegin();
nums ++;
} else {
auto p = m[x];
p->first = x;
p->second = time();
l.erase(p);
l.push_back(*p);
m[x] = l.rbegin();
}
if (nums > K) {
l.pop_front();
nums --;
}
}
int get(int x) {
if (m.find(x) == m.end()) {
return 0;
} else {
auto p = m[x];
if (time() - p->second >= T) {
m.erase(x);
l.erase(p);
return 0;
} else {
p->second = time();
l.erase(p);
l.push_back(*p);
m[x] = l.rbegin();
return x;
}
}
}
}
マルチスレッドの場合、問題が発生します。問題が発生します。
解決方法:内部データ構造を変更するときにロックする
具体点:
// 这里加写锁
l.erase(p);
l.push_back(*p);
m[x] = l.rbegin();
mysqlインデックスデータ構造:B +ツリー
B +ツリーが使用される理由について話す:範囲検索の利点について話す
より良いgitマージとgitリベースについて話します:リベース
利点について話します:はっきりしていません
修辞的な質問
ソースコードを見て、プロジェクトを実行します。これは、インタビューと自己改善の観点から優れています。どちらも重要です。後者はより重要です
どの顔のグループ:クリエイティブ
インタビュアーが4分間紹介しました:とても面白いと思います
三方2020/12/24/14:00-14:55
はじめに(2分)
インターンシップ紹介(12分)
Redisで一般的に使用されるデータ構造:文字列、辞書、リンクリスト、ジャンプリスト、圧縮リスト、セット、順序付きセット
順序付けられたコレクションの実現:スキップリストと圧縮リスト
具体的には、データ量が少ない場合は圧縮リストを使用し、保存方法は線形です。データ量が多い場合は自動的にジャンプテーブルに変換されます。ジャンプリストはと同じです。リンクリスト。1つのノードでリンクされていますが、そのノードとリンクリストは異なり、そのノードにはランダムにいくつかのレイヤーが割り当てられ、同じ数のレイヤーがリンクされます。
スキップテーブルクエリの時間計算量:log(n)
順序集合にクエリ時間計算量のO(1)実装はありますか?順序集合があってはなりません。
Redisの有効期限戦略:いくつかの一般的なlruがあります
これはそうではありません.redisには多くの異なるキーと値はありません。それらの有効期限戦略:ああ、タイムイベントでは、期限切れのものは直接削除されます。また、アクセス時に有効期限が切れると削除されます
以前に使用されたデータベースは何ですか:mysql
エンジンとは:innodb
分離レベルは次のとおりです。繰り返し可能な読み取り
繰り返し読み取りを実現する方法:MVCC
使用される楽観的ロックまたは悲観的ロック:楽観的ロック
MVCCの実現:バージョン番号が増加し、バージョンチェーンがあります。トランザクションが開始されるたびにスナップショットがあり、他のトランザクションが読み取られると、スナップショットが読み取られます。内部トランザクションが変更されるとログが記録されます。ログには、トランザクション内のこの行の変更が記録され、トランザクションのロールバックに使用されます。
binlog、redolog(またはundo log)について聞いたことがありますか:聞いたことはありますが、深く理解していません
innodbのインデックスデータ構造は何ですか:B +ツリー
主キーと非主キーのインデックス:最初に主キーにのみインデックスを作成します。
非主キーについてはどうですか:不明
B +ツリーのリーフノードに格納されているもの:インデックスを含む全体的なデータがそこにあります
ブラウザはURLを入力し、エラーを返します。間違った場所を見つける方法:ステータスコードを使用します。
ステータスコードはなく、エラーは1つだけです。何もありません。。。
dns return sign:dnsのエラーである可能性があり、ドメイン名が存在しない可能性があります
しかし、私が入力したtoutiao.comは、存在することを知っています。はい。DNSクエリ中にエラーが発生した可能性があります。ステップバイステップで確認できます。最初に送信されたときにアクセスしたDNSサーバー(そこにあるはずです、ささやきbb)。おそらく、最寄りのルーターまたはコンピューターにDNSが装備されていません。それは可能ですか(強制的な顔と笑い)
最新のものをどのように知っていますか:DNSのパスを照会すると、コマンドがあるようです
注文内容:この注文の名前を覚えていません。。。
Linuxはどのようにシステムのステータスをチェックしますか:top
トップに表示されるもの:CPU使用率、メモリ使用量、およびいくつかのプロセス情報
インターンシップ中に、Pythonバックエンドはどのようにしてhttp接続を実現しますか?それはdjango:emmであり、webpyapiを介して直接呼び出されます。。。。
あなたのリクエスト、投稿、具体的な実装は何ですか:emmm、C ++から話せますか?
うーん:ソケットを作成し、ソケットにポートを割り当て、接続が確立されるのを待つ必要があります。redisのように接続が確立された後、接続を受信し、ソケットをコピーして新しいポートを割り当て、これを接続します。新しいソケットに割り当てられた元のソケットは、引き続きリッスンします。接続後、ソケット内のバッファの内容を読み取り、内部で処理してから、ソケットを介して送信します。
ソケット監視はどの層ですか:tcp
以前httpについて聞いたのですが、よくわかりませんか?
他に私があなたに尋ねなかったものはありますか:オペレーティングシステム、コンピュータネットワーク、あなたはgolangを使うべきです、pythonはもっとありますか?
C ++にも役立ちます:C ++があるので、もっと知っています
セグメントページストレージが実行されると、メモリに数回アクセスします。メモリへのアクセスはページ数にも関係します。第1レベルのページテーブルの場合は、ページ番号と物理アドレスを1回取得します。一度、それがメモリにない場合は、ディスクにもアクセスします
私が尋ねたセグメントページフォーマット:セグメントページフォーマットは、最初にセグメント内のオフセットを取得し、次に物理アドレスにアクセスします。これは2倍です。
プロセスストレージの分散:スタック、ヒープ、データエリア、コードエリア、共有ライブラリ
コードを配置する場所:コード領域
変数はどこにありますか:静的変数は静的変数領域に配置され、ローカル変数はスタックに配置されます
ポインター:ポインターも静的であり(ソフト(わからない))、直接宣言されてスタックに配置されます
ポインタが指すアドレスによって割り当てられたスペースmalloc:ヒープに入れられます
アルゴリズム
質問をして、あなたが前に何をしたか見てみましょう
求s1中包含s2中字符(不用考虑顺序)的最小子串(长度最小)
s1 = "abcedeabd"
s2 = "abe"
アイデア
スライドウィンドウ:
例のabceのように、s2文字を含む最初の文字列を見つけてから、右に移動してaを上げ、最初の文字列を右側で見つけます。これが次の部分文字列です。すべての部分文字列を見つけて、最も短い部分文字列を見つけます。
顔:これには問題があるので、最初にコードを書いてください。
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
using namespace std;
int main() {
unordered_map<char, int> um1, um2;
unordered_set<char> us;
string s1 = "abcedeabd";
string s2 = "abe";
vector<string> ans;
int left, right;
left = right = 0;
int sum = 0;
for (int i = 0; i < s2.length(); ++ i) {
us.insert(s2[i]);
um1[s2[i]] ++;
sum ++;
}
string s;
um2 = um1;
int i = 0;
while (i < s1.length() && um2[s1[i]] == 0)
i ++;
while (sum > 0) {
if (um2[s1[i]]) {
um2[s1[i]] --;
sum --;
}
s += s1[i];
i ++;
}
ans.push_back(s);
for (; i < s1.length(); ++ i) {
char ch = s[0];
int cnt = 1;
// 找到截取的地方
if (um1[s[0]] == 1) {
while (us.find(s[cnt]) == us.end()) {
// TODO
}
}
while (s[cnt] )
s = s.strsub(1, s.length() -1);
while ()
if (sum == 0){
ans.push_back(s);
um2 = um1;
}
}
cout << "Hello World!" << endl;
}
(17分後)
顔:時間はありません、コードについて話しましょう
私:(コードに直面している)最初に修飾された最初の部分文字列を見つけてから、最初の文字s [0]を削除します。ここでsのs2以外の他の文字を削除する必要があります、ここに問題があります。次の場合[cnt](s2ではすでにs [cnt]になっています)、たまたま削除されたs [0]です。ここでは2つのケースがあります。s2にs [0]が1つしかない場合は、右に行う必要はありません。このとき右にシフトします。s2に複数のs [0]がある場合、他の文字と同じように処理されます。後で書くことがたくさんあると思います。。。
顔:もっと良い解決策があります、後でそれについて考えることができます。
修辞的な質問
Q:本をお勧めします
顔:この種の主観的な推奨は、規制では言えません。
Q:通勤時間
顔:10105.5、あなたはすべて知っている必要があります
私:グループによって違いもあります、ハハ
麺:じゃあ多かれ少なかれ欲しいですか(笑)
上記は面接時の回答であり、他に何も追加されておらず、間違いも訂正されていません。間違いを訂正しても大歓迎です!
私は3つのサイドを通過せず、グループを変更し、2ラウンドを追加し続けました