{"id":21,"date":"2019-03-18T00:00:06","date_gmt":"2019-03-18T00:00:06","guid":{"rendered":"https:\/\/sinyalee.com\/essays\/?p=21"},"modified":"2024-09-02T03:22:45","modified_gmt":"2024-09-02T03:22:45","slug":"interview-question-tesla-autopilot-coding-challenge","status":"publish","type":"post","link":"https:\/\/sinyalee.com\/essays\/?p=21","title":{"rendered":"[Interview Question] Tesla Autopilot Coding Challenge"},"content":{"rendered":"<h3>Background<\/h3>\n<p>This is a real take-home interview problem from Tesla Autopilot. I had an interview with them in May 2017. This is a very interesting and challenging problem.<\/p>\n<p>Before I worked on this problem, the Tesla people didn\u2019t even know whether this problem is NP-hard or not. The standard solution provided by Tesla people used an inferior approximation algorithm. However, as a rock star engineer, I discovered the optimal solution in hours and beat all the people in Tesla.<\/p>\n<p>You can download the problem, data set and my solution in\u00a0<a href=\"https:\/\/drive.google.com\/drive\/folders\/18zJ_gbZUjORN18shHtj9gKmwDgR8zNmU?usp=sharing\">Google Drive<\/a>.<\/p>\n<h3>Problem<\/h3>\n<p>The problem is to find the minimum time path for a Tesla car to drive from one charging station\u00a0<em>s<\/em>\u00a0to another charging station\u00a0<em>t<\/em>\u00a0in a Tesla charging station network. The car has a maximum range of 320km, so it needs to charge in intermediate stations. However, each station has a charging speed in\u00a0<em>km\/hr<\/em>, indicating how many more kilometers the car can drive per hour charging, before the car reach the 320km maximum range.<\/p>\n<p>The input is the names of the starting station and the destination station. A header file is provided with a list of charging stations with their names, coordinates, and charging speeds.<\/p>\n<p>The output is a single line in the following format: starting station name, first intermediate station name, charge time in hrs, second intermediate station name, charge time in hrs, \u2026, \u2026, destination station name.<\/p>\n<h5>Assumptions<\/h5>\n<p>(1) The car starts with a full range of 320km.<br \/>\n(2) Each charging station has a longitude-latitude coordinate. And the Earth is a sphere of radius 6356.752km.<br \/>\n(2) The car travels at a constant speed of 105km\/hr along great circle routes between stations.<\/p>\n<h5>Example<\/h5>\n<p>For example the command\u00a0<code>.\/solution Council_Bluffs_IA Cadillac_MI<\/code> might return:<\/p>\n<pre><code class=\"language-cpp\">\nCouncil_Bluffs_IA, Worthington_MN, 1.18646, Albert_Lea_MN, 1.90293, Onalaska_WI,\n0.69868, Mauston_WI, 1.34287, Sheboygan_WI, 1.69072, Cadillac_MI\n<\/code><\/pre>\n<h5>Tesla\u2019s Solution<\/h5>\n<p>The Tesla\u2019s solution is simple: for each charging station <em>a<\/em>, subdivide it into\u00a0<em>m+1<\/em>\u00a0vertices\u00a0<em>(a, 0), (a, 1), \u2026, (a, m)<\/em>, where vertex\u00a0<em>(a, i)<\/em>\u00a0denotes the state that the car is at charging station\u00a0<em>a<\/em>\u00a0and it currently has\u00a0<em>i\/m * 320 km<\/em>\u00a0range. Then, for every vertex\u00a0<em>(a, i)<\/em>, we add an edge to\u00a0<em>(a, i+1)<\/em>\u00a0with the time equal to the corresponding charging time. Also for any points\u00a0<em>(a, i)<\/em>\u00a0and\u00a0<em>(b, j)<\/em>, we add an edge between them if\u00a0<em>(i-j)\/m * 320 km<\/em>\u00a0is greater or equal to the distance between charging station\u00a0<em>a<\/em>\u00a0and\u00a0<em>b<\/em>, and the time of the edge is the corresponding travel time between these two stations. Then we can simply use any shortest path algorithm to find the shortest path between\u00a0<em>(s, m)<\/em>\u00a0and\u00a0<em>(t, 0)<\/em>\u00a0in the new graph and we can get a solution.<img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7808\/40451247803_939c1d3a84_o_d.png\" alt=\"figure 1\" \/>Please note that this is an approximate algorithm, which means it just does not return the optimal solution. Since Tesla\u2019s original problem description asked for optimal solution, Tesla\u2019s own solution is technically wrong.Also, even though this algorithm is easy to reason about, it is actually much harder to implement comparing to my optimal solution. You will see how simple my code is in a moment.<\/p>\n<p>&nbsp;<\/p>\n<pre><code><\/code><\/pre>\n<h3>A Polynomial Solution<\/h3>\n<p>The optimal solution is not as trivial as Tesla\u2019s solution. We need to prove several lemmas first.<\/p>\n<h5>Lemma 1: If the distance between\u00a0<em>s<\/em>\u00a0and\u00a0<em>t<\/em>\u00a0is greater than the maximum range, the best solution always contain charging time greater than zero. Otherwise, the best solution is to go from\u00a0<em>s<\/em>\u00a0to\u00a0<em>t<\/em>\u00a0directly.<\/h5>\n<p>The proof is trivial.<\/p>\n<h5>Lemma 2: In the optimal solution, we always reach the destination with the zero remaining range.<\/h5>\n<p><strong>Proof:<\/strong>\u00a0Assume that there is an optimal solution with non-zero remaining range\u00a0<em>r<\/em>. Let\u00a0<em>a<\/em>\u00a0be the last station the car charged. And let\u00a0<em>r\u2019<\/em>\u00a0be the extra range we gain from the charging in station\u00a0<em>a<\/em>. Now we construct a new solution where everything stays the same, except we charge\u00a0<em>min(r, r\u2019)<\/em>\u00a0less in station\u00a0<em>a<\/em>.<\/p>\n<p>The new solution is a valid solution: before reaching\u00a0<em>a<\/em>\u00a0it is the same as the old solution; after reaching\u00a0<em>a<\/em>\u00a0and charging for the last time, in the new solution the car always has\u00a0<em>min(r, r\u2019)<\/em>\u00a0less range than the old solution. Because we had range\u00a0<em>r<\/em>\u00a0remaining in the old solution, we will always have at least\u00a0<em>0<\/em>\u00a0range remaining in the new solution. Thus is is a feasible solution.<\/p>\n<p>The new solution also takes less time than the original solution because\u00a0<em>min(r, r\u2019) &gt; 0<\/em>\u00a0so we save some charging time. Thus it is a contradiction with the assumption that the old solution is an optimal solution. Then we proved Lemma 2 is true.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7886\/46693580534_450bbefe4a_o_d.png\" alt=\"figure 2\" \/><\/p>\n<h5>Lemma 3: There always exists an optimal solution where every intermediate station\u00a0<em>b<\/em>\u00a0has the following property: we always charge the car at\u00a0<em>b<\/em>, and we either fully charge the car, or we charge just enough to reach the next station.<\/h5>\n<p><strong>Proof:<\/strong>\u00a0We will prove this lemma by contradiction. Assume that such optimal solution doesn\u2019t exist. Then all solutions has some intermediate station doesn\u2019t have the property Then let\u2019s consider the solution with lowest number of stations in the output. If multiple such solutions exists, let\u2019s consider the solution with lowest number of intermediate stations without the property.<\/p>\n<p>Let\u2019s consider an optimal solution with lowest number of stations in the output. We will prove that in such a solution, we either fully charge the car, or we charge just enough to reach the next station for every intermediate station.<\/p>\n<p>For every three consecutive stations\u00a0<em>a<\/em>,\u00a0<em>b<\/em>, and\u00a0<em>c<\/em>. We will consider all the cases: (1) We don\u2019t charge at station\u00a0<em>b<\/em>\u00a0at all. (2) We charge less than enough to reach\u00a0<em>c<\/em>. (3) We charge just enough to reach\u00a0<em>c<\/em>. (4) We charge more than enough to reach\u00a0<em>c<\/em>\u00a0but do not fully charge. (5) We fully charge the car.<\/p>\n<p>Case (3) and (5) are two permitted cases in Lemma 3. Case (2) is obviously impossible because we are not able to reach\u00a0<em>c<\/em>\u00a0if we didn\u2019t charge enough in\u00a0<em>b<\/em>. Now all we need is to prove that neither case (1) nor case (4) is impossible.<\/p>\n<p>Case (1): Now assume that we don\u2019t charge at station\u00a0<em>b<\/em>\u00a0at all. Then we can construct a new solution which is the same as the old solution except we skip station\u00a0<em>b<\/em>. Since we didn\u2019t charge at\u00a0<em>b<\/em>\u00a0in the old solution, the car has enough range to travel from\u00a0<em>a<\/em>\u00a0to\u00a0<em>b<\/em>\u00a0and\u00a0<em>c<\/em>\u00a0in the old solution. Therefore the car also has enough range to travel from\u00a0<em>a<\/em>\u00a0to\u00a0<em>c<\/em>\u00a0directly in the new solution. Therefore we found a solution with one less station and it takes at most as much time as the old solution. This is a contradiction with the fact that the old solution is an optimal solution with the lowest number of stations. Therefore we proved that case (1) is impossible for any intermediate station in such solutions.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7802\/40451247753_bd7930dd6f_o_d.png\" alt=\"figure 3\" \/><\/p>\n<p>Case (4): Assume that we charge at station\u00a0<em>b<\/em>\u00a0so that we have more than enough gas to reach\u00a0<em>c<\/em>\u00a0but not fully charge.<\/p>\n<p>Because of Lemma 3 we know that\u00a0<em>c<\/em>\u00a0cannot be the destination, otherwise we will reach the destination with non-zero range, which is a contradiction because we just proved case (1) is impossible. Therefore we know\u00a0<em>c<\/em>\u00a0must be an intermediate station as well. There are 3 sub-cases:<\/p>\n<p>Case (4.1): charging station in\u00a0<em>c<\/em>\u00a0is faster than\u00a0<em>b<\/em>. Because we always charge and we charge more than enough in\u00a0<em>b<\/em>. Therefore we can construct a new solution such that we charge a little bit less in\u00a0<em>b<\/em>\u00a0and a little bit more in\u00a0<em>c<\/em>. Since charging station\u00a0<em>c<\/em>\u00a0is faster, the new solution is better, which is a contradiction.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7904\/46693580454_3eb40abe21_o_d.png\" alt=\"figure 4\" \/><\/p>\n<p>Case (4.2): charging station in\u00a0<em>c<\/em>\u00a0is slower than\u00a0<em>b<\/em>. Because we don\u2019t fully charge at\u00a0<em>b<\/em>\u00a0and we always charge at\u00a0<em>c<\/em>. We can construct a new solution such that we charge a little bit more in\u00a0<em>b<\/em>\u00a0and we charge a little bit less in\u00a0<em>c<\/em>. Since\u00a0<em>c<\/em>\u00a0is slower, the new solution is better, which is a contradiction.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7891\/40451247703_6d986de198_o_d.png\" alt=\"figure 5\" \/><\/p>\n<p>Case (4.3): charging station in\u00a0<em>c<\/em>\u00a0is as fast as\u00a0<em>b<\/em>. There are 2sub-cases:<\/p>\n<p>Case (4.3.1): we can skip charging station\u00a0<em>b<\/em>\u00a0in the old solution. Then construct a new solution by skipping\u00a0<em>b<\/em>\u00a0and charge more at\u00a0<em>c<\/em>. We spend as much time in charging, spend at most as much time in traveling, but we have one less station in the new solution. It\u2019s a contradiction with the fact that the old solution is an optimal solution with fewest number of stops.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7802\/40451247753_bd7930dd6f_o_d.png\" alt=\"figure 3\" \/><\/p>\n<p>Case (4.3.2): we cannot skip charging station\u00a0<em>b<\/em>\u00a0in the old solution. Then we charge just enough at\u00a0<em>b<\/em>\u00a0to reach\u00a0<em>c<\/em>\u00a0and we charge more at\u00a0<em>c<\/em>. Then we constructed a new solution with the same travel time and the same charging time, and the total number of stations in the output is the same, and we have one less intermediate station without the property, which is a contradiction.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7904\/46693580454_3eb40abe21_o_d.png\" alt=\"figure 4\" \/><\/p>\n<h4>Algorithm<\/h4>\n<p>The first step of the algorithm is to handle the special case which we don\u2019t need to charge at all. (Lemma 1)<\/p>\n<p>With these Lemmas, we can construct a polynomial algorithm to find a optimal solution by search only paths where all intermediate station has the property in Lemma 3.<\/p>\n<p>The algorithm has multiple passes of computations.<\/p>\n<p>First, we compute the distance\u00a0<em>d_i,j<\/em>\u00a0between every pair of node.<\/p>\n<p>Second, we find the shortest-time path\u00a0<em>a0_i,j<\/em>\u00a0between every pair of stations such that we start with zero range, and reach the destination with zero range, and we never charge to the full range. By Lemma 3 we know that in this case we always charge just enough to reach the next station, thus we can use Floyd-Warshall algorithm to find all\u00a0<em>a1_i,j<\/em>, using\u00a0<em>d_i,j<\/em>\u00a0and the corresponding charging time as edges.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7925\/46693580434_aa30898992_m_d.jpg\" alt=\"figure 6\" \/><\/p>\n<p>Third, we find the shortest-time path\u00a0<em>a1_i,j<\/em>\u00a0between every pair of stations such that we start with full range, reach with zero range, and never reach zero range or full range in between. With Lemma 3 we know that there is only two possibilities: (1) the path has length 2 and the distance is the same as the range. (2) for all pats with length &gt; 2, we know that in all intermediate station we can only charge enough to reach the next station, then the next station must has zero range. Then with the fact that we can only reach zero range in the destination we know that this path has length 3. Therefore we can compute all\u00a0<em>a1_i,j<\/em>\u00a0by brute force with\u00a0<em>O(n^3)<\/em>\u00a0complexity.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7919\/46693580404_b12b1edb0b_o_d.png\" alt=\"figure 7\" \/><\/p>\n<p>Fourth, we find the shortest-time path\u00a0<em>a2_i,j<\/em>\u00a0between every pair of stations such that we start with full range, reach with zero range, and never reach full range in between. They can be computed with all\u00a0<em>a1_i,k<\/em>\u00a0and\u00a0<em>a0_k,j<\/em>\u00a0pairs in\u00a0<em>O(n^3)<\/em>\u00a0time.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7818\/46693580384_5637c646c9_m_d.jpg\" alt=\"figure 8\" \/><\/p>\n<p>Fifth, we find the shortest path\u00a0<em>a3_i,j<\/em>\u00a0between every pair of stations such that we start with full range and reach with full range. This can be computed by using a second pass of Floyd-Warshall algorithm, with\u00a0<em>a2_i,j<\/em>\u00a0with charging time and\u00a0<em>d_i,j<\/em>\u00a0with charging time as edges.<\/p>\n<p><img decoding=\"async\" class=\" article-image\" src=\"https:\/\/farm8.staticflickr.com\/7843\/40451247653_6b9f58ce82_o_d.png\" alt=\"figure 9\" \/><\/p>\n<p>Finally, because of Lemma 2, we can , consider all\u00a0<em>a2_s,t<\/em>\u00a0and all\u00a0<em>a3_s,k<\/em>\u00a0and\u00a0<em>a2_k,t<\/em>\u00a0to find the final solution.<\/p>\n<p>Since every pass is\u00a0<em>O(n^3)<\/em>\u00a0time, the final algorithm is O(n^3).<\/p>\n<h4>My Program<\/h4>\n<p>This is my solution in C++. I used macros intensively. It\u2019s generally not a good practice to use macros since it sometimes cause bugs without generating proper compilation errors. However in this particular problem I found macros very useful to beautify the code.<\/p>\n<p>As you can see, even though the proof of this algorithm is very complicated, the actual program is surprisingly simple. The core of the program is only 10 line long, containing 4 passes of\u00a0<em>n^3<\/em>\u00a0loops.An Even Better Algorithm<\/p>\n<p>With the three lemmas we can find a solution even better than the one above.<\/p>\n<p>This solution is a modification of Tesla\u2019s solution. Instead of considering all possible range at every station, we only construct vertices for the full range, the empty range, the ranges such that it is just enough to reach another station, or the remaining range when we arrive the station from another station with full range. Then there are only O(n^2) vertices in this graph.<\/p>\n<p>And then we add edges between stations only when the first vertex of the edge is full range or the second vertex of the edge is zero range. There are at most\u00a0<em>2n^2<\/em>\u00a0such edges. And we only add edges among vertices corresponding to a single station only if the second vertex of the edge is the next vertex with higher range comparing to the first vertex of the edge. There are at most\u00a0<em>2n^2<\/em>\u00a0such edges. Therefore the total number of edges is at\u00a0<em>O(n^2)<\/em>.<\/p>\n<p>And then we can use Dijkstra algorithm to find the final solution.<\/p>\n<p>The time to add edges is\u00a0<em>O(n^2 log n)<\/em>\u00a0because we need to sort the vertices corresponding to a single station. If we use Dijkstra algorithm with Fibonacci heap, the time complexity to find the shortest path is also\u00a0<em>O(n^2 log n)<\/em>. Therefore, the final time complexity of this algorithm is also\u00a0<em>O(n^2 log n)<\/em>.<\/p>\n<p>Even though this algorithm is faster in complexity and easier to reason about, it is much harder to write the code down because I need to write the Dijkstra algorithm, an\u00a0<em>O(n log n)<\/em>\u00a0sorting algorithm, and a Fibonacci heap. Also in the 303 station network provided by Tesla, this algorithm is not necessarily faster. Therefore I didn\u2019t implement this algorithm.<\/p>\n<h3>Aftermath of the Interview<\/h3>\n<pre><code class=\"language-cpp\">\n#include &quot;network.h&quot;\n#include \n\n#define N 303\n#define G 320.\n#define V 105.\n#define L 4\n#define INF 67108864.\n#define R 6356.752\n#define SQ(x) ((x)*(x))\n#define d2r(x) (x\/180.*3.14159265358979323846264338327950288419716939937510)\n\n#define LOOP(x,y) for(int x=0;x&lt;y;++x)\n#define LOOP(x) LOOP(x,N)\n#define LOOP1 LOOP(i)\n#define LOOP2 LOOP1 LOOP(j)\n#define LOOP3 LOOP(k) LOOP2\n#define RELAX(x,y,u,v) if(y&lt;x){x=y;u=v;}\n\nusing namespace std;\n\nstring sn, tn;\nint s,t;\ndouble a[L][N][N], d[N][N], g[N];\nint A[L][N][N];\n\nbool input(int argc, char** argv) {\n    if (argc != 3) return false;\n    sn = argv[1];\n    tn = argv[2];\n    \n    s = t = 0;\n    while (s &lt; network.size() &amp;&amp; network[s].name != sn) ++s;\n    while (t &lt; network.size() &amp;&amp; network[t].name != tn) ++t; if (s &gt;= network.size() || t &gt;= network.size()) return false;\n    \n    return true;\n}\n\nstring output(int l, int i, int j) {\n    if (i == j) return &quot;&quot;;\n    if (l == 0) {\n        if (A[l][i][j] &lt; 0)\n            return &quot; &quot; + to_string(d[i][j]*g[i]\/V) + &quot; &quot; + network[j].name;\n        return output(0, i, A[l][i][j]) + output(0, A[l][i][j], j);\n    }\n    if (l == 1)\n        return &quot; &quot; + network[A[l][i][j]].name + &quot; &quot;\n        + to_string((d[i][A[l][i][j]]+d[A[l][i][j]][j]-G) * g[A[l][i][j]] \/ V)\n        + &quot; &quot; + network[j].name;\n    if (l == 2)\n        return output(1, i, A[l][i][j]) + output(0, A[l][i][j], j);\n    if (A[l][i][j] == -1)\n        return output(2, i, j) + &quot; &quot; + to_string(g[j]\/V);\n    if (A[l][i][j] == -2)\n        return &quot; &quot; + network[j].name + &quot; &quot; + to_string(d[i][j] * g[j] \/ V);\n    return output(3, i, A[l][i][j]) + output(3, A[l][i][j], j);\n}\n\nint main(int argc, char** argv)\n{\n    if (!input(argc, argv)) {\n        cout &lt;&lt; &quot;Error: requires initial and final supercharger names&quot; &lt;&lt; endl; return -1; } LOOP1 g[i] = V \/ network[i].rate; LOOP2 d[i][j] = R*2.*asin(sqrt(SQ(sin(d2r((network[i].lat-network[j].lat)\/2.))) + cos(d2r(network[i].lat))*cos(d2r(network[j].lat)) * SQ(sin(d2r((network[i].lon-network[j].lon)\/2.))))); LOOP2 if (d[i][j] &gt; G) d[i][j] = INF;\n    if (d[s][t] &lt;= G) {\n        cout &lt;&lt; sn + &quot; &quot; + tn &lt;&lt; endl; return 0; } LOOP(l,L) LOOP2 a[l][i][j] = INF; LOOP(l,L) LOOP2 A[l][i][j] = -1; LOOP2 a[0][i][j] = d[i][j] * (g[i]+1.); LOOP3 RELAX(a[0][i][j], a[0][i][k] + a[0][k][j], A[0][i][j], k); LOOP3 if (d[i][k] + d[k][j] &gt;= G)\n        RELAX(a[1][i][j], G + (d[i][k]+d[k][j]-G)*(g[k]+1.), A[1][i][j], k);\n    \n    LOOP3 RELAX(a[2][i][j], a[1][i][k] + a[0][k][j], A[2][i][j], k);\n    \n    LOOP2 a[3][i][j] = a[2][i][j] + g[j] * G;\n    LOOP2 RELAX(a[3][i][j], d[i][j] * (1. + g[j]), A[3][i][j], -2);\n    LOOP3 RELAX(a[3][i][j], a[3][i][k] + a[3][k][j], A[3][i][j], k);\n    \n    int m = INF, M = -1;\n    LOOP1 RELAX(m, a[3][s][i] + a[2][i][t], M, i);\n    if (M &lt; 0)\n        cout &lt;&lt; &quot;No path exists.&quot; &lt;&lt; endl;\n    else\n        cout &lt;&lt; sn + output(3, s, M) + output(2, M, t) &lt;&lt; endl;\n    \n    return 0;\n}\n<\/code><\/pre>\n<p>I didn\u2019t get a job offer in the end. The coding challenge went well. The recruiter submitted my information to the hiring managers of two different teams. And then the asked me where I was from. I said \u201cChina\u201d. Then the recruiter just stopped the interview process abruptly and denied my applications to both teams.<\/p>\n<p>Lessons learned:<\/p>\n<p>(1) Always reveal your ethnicity when applying for jobs. That\u2019s why I have my photo in my homepage. The company is going to know your ethnicity sooner or later. It\u2019s better to get discriminated before the interview starts so you don\u2019t waste time. Also, I believe racism is fundamentally wrong ethically. If a company is practicing racism, you know they are evil and\u00a0<a href=\"https:\/\/www.theguardian.com\/technology\/2017\/may\/18\/tesla-workers-factory-conditions-elon-musk\">it would not be a good company to work for, regardless of your ethnicity.<\/a>\u00a0So reveal your ethnicity is a good way to efficiently avoid evil companies like Tesla.<\/p>\n<p>(2) Never ever work on take-home interview problems. Your time is precious. For every hour you spend on your job application, you need to make sure someone\u00a0<strong>at your level<\/strong>\u00a0spend an hour on your application. This is very important to make sure they take your application seriously. 1-to-1 interviews are expensive for companies. Thus they give 1-to-1 interviews only after they review your background and experience, and think there is a good chance they will hire you. However, take-home problem is basically free for them. Their best strategy is to give take home problems to as many people as possible, and only start looking into your background and experience after you finish the problem. It means there is a good chance you will be rejected by something on your resume, even after you spend a long time working on their take-home interview problem.<\/p>\n<p>Anyway, this problem is still my favorite interview problem of all time. There are three reasons.<\/p>\n<p>(1) There are so much depth in this problem. There is an exponential brute force algorithm. There is an approximation algorithm. And we can find two polynomial algorithms if we spent time studying the properties of the optimal solutions. One of the polynomial algorithms is so simple that it just contains four 3D loops.<\/p>\n<p>(2) This problem shows how much better I am comparing to the Tesla people.<\/p>\n<p>(3) The background of this problem is so good. It vividly portrays\u00a0<a href=\"https:\/\/www.nytimes.com\/2017\/10\/05\/automobiles\/wheels\/electric-cars-charging.html\">the constant anxiety of the miserable Tesla owners.<\/a>\u00a0They need to worry about the battery life of their cars constantly since the range is so short and it\u2019s so difficult to find a charging station. Even if they can find a charging station, after every hour of driving, they need to drive half an hour to the next Tesla supercharger and charge for half an hour. By comparison, with my very fuel inefficient Range Rover I can drive from Boston to Washington, D.C. without stopping at a gas station.<\/p>\n<p>Sometimes I wonder why Tesla interview job candidates with a problem showing how bad their products are. But after I think about the fact that they couldn\u2019t even solve this problem, I believe I know the answer.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Background This is a real take-home interview problem from Tesla Autopilot. I had an interview with them in May 2017. This is a very interesting and challenging problem. Before I worked on this problem, the Tesla people didn\u2019t even know whether this problem is NP-hard or not. The standard solution provided by Tesla people used [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[],"class_list":["post-21","post","type-post","status-publish","format-standard","hentry","category-coding"],"_links":{"self":[{"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=\/wp\/v2\/posts\/21","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=21"}],"version-history":[{"count":27,"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=\/wp\/v2\/posts\/21\/revisions"}],"predecessor-version":[{"id":129,"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=\/wp\/v2\/posts\/21\/revisions\/129"}],"wp:attachment":[{"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=21"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=21"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sinyalee.com\/essays\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=21"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}