就活で無双!?スタンフォードの友達が絶賛する一冊の英語の本


この文章のターゲット

本記事は、コンピュター界隈の人間にとっての英語の有用性を述べた上で、

  • コーディングやアルゴリズムの揺るぎない基礎力
  • エンジニアとして周りとの差別化が図れる英語力

の両方が欲しいと考えている人に、一冊の本を紹介するものです。

はじめに

昨年の夏、カリフォルニア大学バークレー校へ留学する機会があったのですが、そのとき Dropbox でインターンをするひとりの学生と出会いました。普段スタンフォードで CS を専攻する彼は、そのような企業で働けることに大きなやりがいを感じているようでした。実際、その目は西海岸を照らす太陽よりも輝き、その手は自分の生んだコードが世界を変えているという喜びにキーボードの上を軽やかに舞っているようでした。

そんな彼に教えてもらったのが、今回この記事で紹介する本です。スタンフォード生から「マジでこれやっとけば最強」とお墨付きをもらった一冊ということになります。

コンピュータと英語

英語という相棒

大学でコンピュータを専攻していると、どうしても英語が必要な場面というのがあると思います。それも、論文や技術書などで見るようなコンピュータ用語が混ざった英語が、です。

また、もしエンジニアとして飯を食うのであれば、英語は強力な武器になると思われます。Stack Overflow や Quora などのサービスに加え、あらゆる公式ドキュメントの原文がストレスなく読める英語力は、トニー・スタークにとってのジャービスにも匹敵する頼もしい相棒です。

たとえば

たとえば、仮に $O(2^n)$ の恐ろしさを知りたい気分になったとします。まだ学びたての C++ で時間を計測しようと思って調べた結果、

rec.cppの一部
auto start1 = high_resolution_clock::now();
f1(n);
auto stop1 = high_resolution_clock::now();

のようなコードを書きました。これをコンパイルすると、ちょっと怒られました。

warningメッセージの一部
rec.cpp:28:9: warning: 'auto' type specifier is a C++11 extension [-Wc++11-extensions]
        auto start1 = high_resolution_clock::now();
        ^

要するに、コンパイラが古いよということなのですが、ここで

「C++ のコンパイラのデフォルトを C++11 に設定する方法」

を知りたくなります。もしくは、そんな設定をしていいのかナンセンスなのかを知りたくなります。というか、 C++ もコンパイラ界の常識も何もかもわからないのでとりあえず何かの情報を得たくなります。

「大教室の一番後ろの席で昼寝してる大学生のやる気よりも低い」と評されるグーグラビリティを持つ私に最初に浮かんだ検索ワードは「C++11 コンパイラ デフォルト 設定 方法」でした。最上位の検索結果は

などでした(2020/03/28 アクセス)。

一方で、英語で「C++11 how to set as default」といういかにも安直な調べ方をすると、どうでしょう。

という Stack Overflow のページが一番上に表示されました。同じ疑問を持つ人が世界にはいて、それに答えてくれる人もまたいる、英語のエンジニア界隈は日本語のそれより圧倒的に広く、大きいのです。

英語は知恵を世界に増やす

シン・ゴジラで矢口蘭堂は

「知恵は多ければ多いほうが良い」

と言いました。

また、古くからの伝承によると

「情報の少なさと貧弱なグーグル能力が混じり合ったとき、世界には虚無の時間が訪れる」

といわれています。

その知恵はにわか雨でできた水たまりよりも浅く、検索で無駄にした時間は何万個ものカップ麺に相当すると言われる私が自信をもって主張できることは、「英語とは自分が使える知恵の世界総和を爆発的に増やし、時間軸への虚無の到来を大幅に減らすものである」ということです。

Cracking the Coding Interview

英語で読むということ

とはいえ、「英語が読める」と「英語で読める」には大きな差があります。いきなり全ての検索を英語ですると決めても、もって3分で挫折します。読めたとしても、そこから情報を自分に吸収するのはまた別の話だからです。

スタンフォード生が教えてくれた一冊

こんなときは、わかりやすくて面白い本を一冊読むのが一番良いです。コンピュータ界あるあるの言い回しだったり、検索したらヒットしやすそうなワードだったりが自分の中に蓄積されていきます。また、内容が面白ければ挫折しません。自分が日本語で知っている知識が出てくるので「英語でこう言うんだ!」という感動が頻繁にあるからです。

そんな一冊として私が最強におすすめするのが、これです。

Cracking the Coding Interview。さっき自分で写真を撮ったのですが、失敗してちょっとボケています。

あちらでは学生を中心にしてだいぶ有名なようで、Amazon.com における Interview Book のベストセラーだそうです。

Coding Interview

シリコンバレーでのエンジニアの採用

Interview とは何か、ということについて少しだけ述べます。

シリコンバレーでは、 Coding Interview とよばれる面接を経てエンジニアを採用するのが一般的です。

簡単に言えば、どれだけ実装できるの?を測るテストなのですが、競プロのようなものではありません。数十分の試験時間の中で面接官から一つだけ難問が出され、ホワイトボードの前に立って方針や具体的な実装方法、基礎的な知識を説明します。

基本的にスラスラ解ける問題ではないので、面接官からヒントをもらいながら、自分の思考プロセスや使えそうなアルゴリズムについて述べます。基本的なアルゴリズムについての説明が求められることが多々あり、直感や経験よりも重厚な基礎があることを求められます。

アメリカの学生インターン

MIT や スタンフォード、UC Berkley、カーネギーメロンのような名門大学の EECS (または CS) 専攻の学生の間では、夏休みを利用して GAFA や Twitter、Uber、Slack などの IT 企業でインターンをするのが一般的になっています。これにも Coding Interview があり、そのための有名な一冊が Cracking the Coding Interview ということでした。

ちなみに、こういうところでインターンをすると夏休みだけで300万から400万円ほど稼げるんだそうです。

Cracking the Coding Interview の何がいいか

スタンフォードの彼が言っていたこと

冒頭の昨年夏の話に戻ります。スタンフォードの彼が「この本マジで最高だよ」という感じの口ぶりだったので、何がいいのか聞いたのですが、

"Because many problems you get asked in the real interviews are very similar to the ones written in the book, even if not the same."

と言っていました。Google からも Facebook からもインターンのオファーを得てる彼が言うんだから間違いない、と盲目的になった私は、帰国してすぐこの本をポチりました。それから半年の間、この分厚い一冊は一度も開かれることはなかったのですが、今猛烈な感動を私にもたらしています。これがマジで良いんです。

説明がわかりやすい

私が感じるこの本の良さは「いちいち説明が分かりやすい」ということです。

本「こういうところにつまづきやすいです」
私「そうそうそうそうそれそれそれそれ!!!」

本「多くの学生はこう答えてしまいます」
私「あ、ワイや」

私「いや、どういうこと?分かんねえわ」
本「...ということがわかりづらく感じる学生も多いのでもう少し具体的に説明します」

といった具合で、かゆいところに手が届く至高の逸品です。

このことは非常に大事だと思われます。読みながらつっかえつっかえだと疲れるし、何よりもモチベが続きません。この本は挫折を本気で防いでくれます。

アメリカの学生がどんな勉強をするのか雰囲気がつかめる

何気に嬉しいことが、あちらの学生の勉強の仕方がなんとなく感じられるということです。いろいろな小話も載っていて、それが面白い。

シリコンバレーの優秀な学生たちも自分と似たところでつまづくんだな、ってクスリとできるし、なんか親近感がわきます。

基礎からの構築

Cracking the Coding Interview の良さは、なんといっても「重厚な基礎の構築」でしょう。本当に基礎が充実します。Big O から始まり、データ構造、概念とアルゴリズム、細かな知識などが豊富な問題とともに示され、更にその一問一問の質が非常に高いです。

一方で、レベルの高い問題は結構難しいです。たとえば計算量を求める問題 (Example 12, VI | Big O, p. 51) はこんな感じです。

void permutation(String str) {
    permutation(str, "");
}

void permutation(String str, String prefix) {
    if (str.length() == 0) {
        System.out.println(prefix);
    } else {
        for (int i = 0; i < str.length(); i++) {
            String rem = str.substring(0, i) + str.substring(i + 1);
            permutation(rem, prefix + str.charAt(i));
        }
    }
}

コードを書いてみる問題 (*10.11, Chapter 10 | Sorting and Searching, *, p. 151) もあります。

Peaks and Valleys: In an array of integers, a "peak" is an element which is greater than or equal to the adjacent integers and a "valley" is an element which is less than or equal to the adjacent integers. For example, in the array {5, 8, 6, 2, 3, 4, 6}, {8, 6} are peaks and {5, 2} are valleys. Given an array of integers, sort the array into an alternation sequence of peaks and valleys.

EXAMPLE
Input: {5, 3, 1, 2, 3}
Output: {5, 1, 3, 2, 3}

結構スラスラ読める

この本は結構スラスラ読めます。おそらく何度も推敲して丁寧に書き直したんだと思います。英語でのコーディングの学習をするなら、間違いなくオススメできる本です。

さいごに

誰しもこういう属性の人々に遭遇したことがあると思います。

  • スタバで、キーボードカタカタ
  • 表情、なんだか誇らしげ
  • エンターキー、カッターン
  • テーブルを見ると MacBook Air
  • でも LINE しかしてない

そう、ドヤラーです。

最後に、この本の最強の用途を述べます。Amazon からこの辞書のような本が届いたら、ドヤリング蔓延るスタバの大テーブルへ座って、この本の真ん中あたりのページを開いてください。涼しそうな顔でそれっぽいことを書き込んでみます。私の場合、

Dijkstra's algorithm
public static void main(String[] args)
syntax highlight

などと訳のわからないことを書きました。すると不思議なことに、ひとり、またひとりと MacBook Air を閉じ、そそくさと帰っていったのです。書籍として優れているということは書いたとおりです。が、この本はそれと同時に MacBook Air にも打ち勝つ最強のドヤアイテムにもなるのです。

ドヤリング族を蹴散らしたあと、満足げな表情を浮かべながら帰路についた私はふと思いました。「あれ、俺何やってんだろ」

付録A

O(2^n) の恐ろしさを知りたい気分のとき役立つプログラム

rec.cpp
#include <iostream>
#include <algorithm>
#include <chrono>
using namespace std;
using namespace std::chrono;

int f1(int n) {
        if (n <= 1) {
                return 1;
        }
        return 2 * f1(n - 1);
}

int f2(int n) {
        if (n <= 1) {
                return 1;
        }
        return f2(n - 1) + f2(n - 1);
}

int main()
{
        int n;

        cout << "Input N: ";
        cin >> n;

        auto start1 = high_resolution_clock::now();
        f1(n);
        auto stop1 = high_resolution_clock::now();
        auto duration1 = duration_cast<microseconds>(stop1 - start1);
        cout << "Time taken by 2 * f(n - 1): "
        << duration1.count() << " microseconds" << endl;
        cout << endl;

        auto start2 = high_resolution_clock::now();
        f2(n);
        auto stop2 = high_resolution_clock::now();
        auto duration2 = duration_cast<microseconds>(stop2 - start2);
        cout << "Time taken by f(n - 1) + f(n - 1): "
        << duration2.count() << " microseconds" << endl;

        return 0;
}