ByteDanceインターンシップインタビュー:変更なしで一般に公開されています。彼が合格したかどうかを確認しますか?

彼が合格したと思いますか

片側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ラウンドを追加し続けました

おすすめ

転載: blog.csdn.net/Python6886/article/details/111770315