楼主: 大木虫
跳转到指定楼层
上一主题 下一主题
收起左侧

Elements of Programming Interviews 白班编程记录,求挑刺求反馈

 
🔗
 楼主| 大木虫 2018-11-5 00:56:46 | 只看该作者
全局:
445. Add Two Numbers II
这道题有多种解法:反转链表,stack,转成数字相加再转回,递归

我挑了我认为最麻烦的一种:递归,因为其它写法太直接,写起来达不到训练的效果。
本题递归的核心是tail recursion,代码如下(写了40分钟左右)

  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. *     int val;
  5. *     ListNode *next;
  6. *     ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. */
  9. class Solution {
  10. public:
  11.     ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
  12.         /* 0. MISC */
  13.         if(!l1 && !l2)return NULL;
  14.         if(!l1 || l1->val == 0)return Copy(l2);
  15.         if(!l2 || l2->val == 0)return Copy(l1);
  16.         
  17.         /* 1. prep */
  18.         int l1Size = Size(l1), l2Size = Size(l2);
  19.         ListNode *shortList, *longList;
  20.         if(l2Size > l1Size){
  21.             longList = l2; shortList = l1;
  22.         }else{
  23.             shortList = l2; longList = l1;
  24.         }
  25.         int diff = abs(l1Size - l2Size);
  26.         
  27.         /* 2. key algo */
  28.         ListNode *head = AddListRec(longList, shortList, diff);
  29.         if(head->val >= 10){
  30.             ListNode* tmp = new ListNode(head->val/10);
  31.             head->val %= 10;
  32.             tmp->next = head;
  33.             head = tmp;
  34.         }
  35.         
  36.         /* 3. answer */
  37.         return head;
  38.     }
  39.    
  40.     ListNode* AddListRec(ListNode *l1, ListNode *l2, int diff){
  41.         /* base case */
  42.         if(!l1 && !l2)return NULL;
  43.         
  44.         ListNode * node = new ListNode(0), *child;
  45.         if(diff > 0){
  46.             child = AddListRec(l1->next, l2, diff-1);
  47.             node->val += l1->val;
  48.         }else{
  49.             child = AddListRec(l1->next, l2->next, diff);
  50.             node->val += l1->val + l2->val;
  51.         }
  52.         
  53.         if(child){
  54.             node->val += child->val/10;
  55.             child->val %= 10;
  56.         }
  57.         
  58.         node->next = child;

  59.         return node;
  60.     }
  61.    
  62.     ListNode* Copy(ListNode* l){
  63.         ListNode* dummy = new ListNode(0);
  64.         ListNode* current = dummy;
  65.         
  66.         while(l){
  67.             current->next = new ListNode(l->val);
  68.             l = l->next;
  69.             current = current->next;
  70.         }
  71.         
  72.         ListNode * head = dummy->next;
  73.         delete dummy;
  74.         
  75.         return head;
  76.     }
  77.    
  78.     int Size(ListNode* l){
  79.         int ans = 0;
  80.         while(l){
  81.             l = l->next;
  82.             ++ans;
  83.         }
  84.         return ans;
  85.     }
  86. };
复制代码
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-25 00:22:25 | 只看该作者
全局:
结束了一些面试,开始准备下一波面试,18天的时间,争取把高难度高频旧题做30~40道,medium-hard高频新题做30~40道,实现最近两个月的onsite面经,以高频为主
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-25 00:26:50 | 只看该作者
全局:
主要的课题是graph, DFS, BFS, backtracking, tree, DP, array, string, stack.
follow up 的主要课题是scalability
会练一点OOD
不练design

补充内容 (2018-11-25 00:27):
对了还有linked list
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-25 01:53:49 | 只看该作者
全局:
今天做热身
LC 482 (easy)
LC 412 (easy)
LC 347 (medium)
都是一遍过,平均用时12分钟
下午有心情的话,再写几个偏简单的题目
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-26 06:03:26 | 只看该作者
全局:
今天做了一题LC 904,然后总结了最近两周面经15题左右,作为明天起的刷题指导
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-27 03:19:26 | 只看该作者
全局:
遇到了阻碍,我这样做下去效果堪忧。需要作出修改。

我面试的公司是Google,面试日期是12/14,不算今天的话还有16天的准备时间。我的模式是脱产准备,每天6小时。16天不多,但还是相对充足的。不过如果没有章法,那么就会出现问题。为此,我决定利用今天制定一套比较可行的计划,模仿之前准备Google phone screen的模式。

为了通过面试,我需要几个核心能力:
1. 把题听懂并想出来的能力
2. 让面试官听懂我想法的能力
3. 把不会的题说出个一二三的能力
4. 把答案迅速正确白板码出来的能力
5. 在陌生环境下稳定发挥的能力

我们从这几个点一个个分解,作出未来16天的确定的脚踏实地的计划。

1. 把题听懂并想出来的能力
对于google来讲,这个能力是相对单调的,就是对数据结构和算法的熟练运用。我在此更加依靠系统的对数据结构和算法的训练,而不是散乱的面经,因为这里训练的是得出答案思路,触类旁通,举一反三的能力,强调的是对主要知识点的熟练运用和融汇贯通。我的训练方法是集中训练高频知识点,不考虑公司tag。对于google,我认为的高频知识点有如下几个:
     array/string
     binary tree/BST/tree traversal
     graph/DFS/BFS
     backtracking
     hashmap/hashtable
     priority queue
     dynamic programming/memoization
     trie
     linked list
我会使用9天的时间进行知识点集中训练,训练目的是掌握知识点,梳理标准化解题步骤,以及提高对syntax的熟练度和码速,大致时间分配如下:
阶段一:树,图类,4天,总共写20题左右,每天做1~2道旧经典medium/hard,再做2~4道新medium/hard
阶段二:string/array/hashtable,3天,总共写15题左右,每天做1~2道旧经典medium/hard,再做2~4道新medium/hard
阶段三:dynamic programming,2天,总共写10题左右,每天做1~2道旧经典medium/hard,再做2~4道新medium/hard
这大概是之前的强度,再高的话难以坚持。9天45题,够多了。我估计这45题中AC之前看discussion的次数不会超过3次,这也是之前的表现。

2. 让面试官听懂我想法的能力 3. 把不会的题说出个一二三的能力 4. 把答案迅速正确白板码出来的能力 5. 在陌生环境下稳定发挥的能力
这些放一起来讨论,因为它们都是在真是面试情境中被考验的。
我的办法是用高频medium-hard和新题medium-hard来进行白板模拟,每天使用3小时来模拟2题,持续7天,题目从高频面经和LC里面出

3. 面经,押题
押题是非常有用的,所以单独拿出来讲。
对于我来讲就是看面经,总结面经,这是一个比较难的过程,因为总有一些面经题我写不出来。
计划是把近期的面经全写完,高频题要写出来,非高频得知道怎么想。从最近期一个月开始逐渐扩展。每天花3小时研究面经,持续7天,能做多少是多少。我会在面经贴下面直接贴我想的答案。不会的就展开讨论。

所以总结一下,计划如下:
第一阶段:高频知识点熟练掌握贯通,提高码力,练习标准化解题流程,9天
第二阶段:白板模拟练习训练心理素质和标准化执行,看面经押题,两者交替进行,7天

在以上过程的实践中,我格外注重几点:
    思考一定要深,要自发,要有拉扯思维的感觉
    要从解题中寻得乐趣
    对于每一道题都要给出一两句的总结,并思考与其他题目联系,变型和转换
    要把操作细节规程化习惯化
    要每天8小时规律的睡眠

大概就是这样,希望这套计划能起到作用。
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-27 05:09:27 | 只看该作者
全局:
LC 016 three sum closest,得出了N^2 * logN的解法,N^2没有思路,看了topics和部分discuss title,说要用two pointers和sorting解,又想了60分钟,终于tm想出来了N^2解,是先用sort进行preprocess,然后用类似于trapping rain water的two pointers向中间合拢的方法来解。感觉想的好累好难。。。

补充内容 (2018-11-27 05:09):
topics是指LC的related topics
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-28 02:58:27 | 只看该作者
全局:
LC 489 robot cleaner 第三遍,AC in 28 min
idea: backtracking
tips: get your coder-friendly custom API defined before implementation

compile errors:
missing semicolon
swapped function signatures (decode/encode backwards)
missed i/j with loc.first/loc.second

no run time errors

C++ Code:
  1. /**
  2. * // This is the robot's control interface.
  3. * // You should not implement it, or speculate about its implementation
  4. * class Robot {
  5. *   public:
  6. *     // Returns true if the cell in front is open and robot moves into the cell.
  7. *     // Returns false if the cell in front is blocked and robot stays in the current cell.
  8. *     bool move();
  9. *
  10. *     // Robot will stay in the same cell after calling turnLeft/turnRight.
  11. *     // Each turn will be 90 degrees.
  12. *     void turnLeft();
  13. *     void turnRight();
  14. *
  15. *     // Clean the current cell.
  16. *     void clean();
  17. * };
  18. */

  19. /* backtracking problem, define custom APIs first */

  20. class Solution {
  21. private:
  22.     int state;   

  23. public:
  24.     Solution(): state(0){}
  25.    
  26.     void cleanRoom(Robot& robot) {
  27.         /* 0. MISC */
  28.         
  29.         /* 1. prep */
  30.         unordered_set<string> visited;
  31.         
  32.         /* 2. key algo */
  33.         CleanRoomRec(&robot, &visited, {0, 0});
  34.         
  35.         /* 3. answer */
  36.         /* void, no return */
  37.     }
  38.    
  39.     void CleanRoomRec(Robot* robot, unordered_set<string>* visited, pair<int, int> loc){
  40.         /* before branching */
  41.         if(visited->find(Encode(loc)) != visited->end())return;
  42.         visited->emplace(Encode(loc));
  43.         robot->clean();
  44.         
  45.         /* branching */
  46.         vector<string> directions = {"N", "E", "S", "W"};
  47.         vector<pair<int, int>> moves = {pair<int, int>(-1, 0), pair<int, int>(0, 1), pair<int, int>(1, 0), pair<int, int>(0, -1)};
  48.         for(int i = 0; i < directions.size(); ++i){
  49.             string dir = directions[i];
  50.             string revDir = directions[(i+2)%4];
  51.             if(CanEnter(dir, robot)){
  52.                 TurnTo(dir, robot);
  53.                 robot->move();
  54.                 CleanRoomRec(robot, visited, {loc.first + moves[i].first, loc.second + moves[i].second});
  55.                 TurnTo(revDir, robot);
  56.                 robot->move();
  57.             }
  58.         }
  59.         
  60.         /* done */
  61.     }
  62.    
  63.     void TurnTo(string dir, Robot* robot){
  64.         int target = 0;
  65.         if(dir == "N")target = 0;
  66.         if(dir == "E")target = 1;
  67.         if(dir == "S")target = 2;
  68.         if(dir == "W")target = 3;
  69.         while(state != target){
  70.             robot->turnRight();
  71.             state += 1;
  72.             state %= 4;
  73.         }
  74.     }
  75.         
  76.     void TurnAround(Robot* robot){
  77.         robot->turnRight();
  78.         robot->turnRight();
  79.         state += 2;
  80.         state %= 4;
  81.     }
  82.    
  83.     bool CanEnter(string dir, Robot* robot){
  84.         TurnTo(dir, robot);
  85.         bool ans = robot->move();
  86.         if(ans){
  87.             TurnAround(robot);
  88.             robot->move();
  89.         }
  90.         return ans;
  91.     }
  92.   
  93.     string Encode(const pair<int, int>& loc){
  94.         return to_string(loc.first) + " " + to_string(loc.second);
  95.     }
  96.    
  97.     pair<int, int> Decode(const string& loc){
  98.         int div = loc.find(" ");
  99.         string strI = loc.substr(0, div);
  100.         string strJ = loc.substr(div + 1);
  101.         return {stoi(strI), stoi(strJ)};
  102.     }
  103. };
复制代码
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-28 04:22:24 | 只看该作者
全局:
428. Serialize and Deserialize N-ary Tree (hard)

1. Understand Problem at 2 min
2. Get key concept at 8 min
3. Algorithm draft part 1 at 12 min
4. Detailed derivation part 1 at 16 min
5. Code draft part 1 at 19 min
6. Algorithm draft part 2 at 30 min
7. Detailed derivation at 35 min
8. Code draft at 49 min
9. solution AC at 59 min

compile error:
remember to pass pointer reference function(&param)

Runtime error:
incomplete answer (only root node)
had one boolean logic reversed
missed null case

主要思路是DFS,序列化和反序列化的思路都是DFS,反序列化要注意一些string parsing的细节,最好在序列化的时候就把string格式做的友善一些。
Ntree的序列化和binary tree的序列化想法类似,但是写法有一些差异,主要原因在于不知道每个node有几个children,与其说是tree序列化,这题更像是图学历恶化(graph serialization)。很好的题。

C++ code:
  1. /*
  2. // Definition for a Node.
  3. class Node {
  4. public:
  5.     int val = NULL;
  6.     vector<Node*> children;

  7.     Node() {}

  8.     Node(int _val, vector<Node*> _children) {
  9.         val = _val;
  10.         children = _children;
  11.     }
  12. };
  13. */
  14. class Codec {
  15. public:

  16.     // Encodes a tree to a single string.
  17.     string serialize(Node* root) {
  18.         string answer = " ";
  19.         SerializeRec(root, &answer);
  20.         cout << "ans: " << answer << endl;
  21.         return answer;
  22.     }
  23.    
  24.     void SerializeRec(Node* node, string* answer){
  25.         if(!node)return;
  26.         (*answer) += to_string(node->val);
  27.         (*answer) += " ";
  28.         if(!node->children.empty()){
  29.             (*answer) += "[";
  30.             for(auto child: node->children){
  31.                 SerializeRec(child, answer);
  32.             }
  33.             (*answer) += "] ";
  34.         }
  35.     }
  36.    
  37.     char nextChar(string data, int index){
  38.         while(index < data.size() && data[index] == ' ')++index;
  39.         return data[index];
  40.     }
  41.    
  42.     int nextNum(string answer, int* index){
  43.         string numStr;
  44.         while(*index < answer.size() && !isdigit(answer[*index]))++(*index);
  45.         while(*index < answer.size() && isdigit(answer[*index]))numStr += answer[(*index)++];
  46.         return stoi(numStr);
  47.     }
  48.    
  49.     // Decodes your encoded data to tree.
  50.     Node* deserialize(const string& data) {
  51.         /* 0. MISC */
  52.         if(data == " ")return NULL;
  53.         
  54.         /* 1. prep */
  55.         int index = 0;
  56.         
  57.         /* 2. key algo, 3.answer*/
  58.         return DeserializeRec(data, &index);
  59.     }
  60.    
  61.     Node* DeserializeRec(const string& data, int* index){
  62.         int val = nextNum(data, index);
  63.         Node* node = new Node(val, {});
  64.         if(nextChar(data, *index) == '['){
  65.             while(nextChar(data, *index) != ']')
  66.                 node->children.emplace_back(DeserializeRec(data, index));
  67.             while(data[*index] != ']')++(*index);
  68.             ++(*index);
  69.         }
  70.         return node;
  71.     }
  72. };

  73. // Your Codec object will be instantiated and called as such:
  74. // Codec codec;
  75. // codec.deserialize(codec.serialize(root));
复制代码



补充内容 (2018-11-28 04:25):
follow up:用stack写一遍迭代版本
回复

使用道具 举报

🔗
 楼主| 大木虫 2018-11-28 06:25:14 | 只看该作者
全局:
LC 99. Recover Binary Search Tree (hard)
没有仔细计时,但是临场应该可以35分钟AC,这是估算上限
我用的是in-order traversal解,space complexity O(h),不是constant space。constant space据说要用Morris Traversal,这我还不会,要学一学。in-order解唯一有些复杂的地方就是一堆pointer的操作

C++ code:
  1. /**
  2. * Definition for a binary tree node.
  3. * struct TreeNode {
  4. *     int val;
  5. *     TreeNode *left;
  6. *     TreeNode *right;
  7. *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12.     void recoverTree(TreeNode* root) {
  13.         /* 1. prep */
  14.         TreeNode *prev = NULL, *first = NULL, *second = NULL;
  15.         
  16.         /* 2. key algo */
  17.         FindSwappedNodesRec(root, &prev, &first, &second);
  18.         swap(first->val, second->val);
  19.         
  20.         /* 3. answer */
  21.         /* no return */
  22.     }
  23.    
  24.     void FindSwappedNodesRec(TreeNode* node, TreeNode** prev, TreeNode** first, TreeNode** second){
  25.         if(!node)return;
  26.         FindSwappedNodesRec(node->left, prev, first, second);
  27.         
  28.         if(*prev != NULL){
  29.             if((*prev)->val > node->val){
  30.                 if(*first == NULL)*first = *prev;
  31.                 *second = node;
  32.             }
  33.         }
  34.         *prev = node;
  35.         
  36.         FindSwappedNodesRec(node->right, prev, first, second);
  37.     }
  38. };
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表