# 求職筆記 ## LeetCode 刷題指南 #### 1. [**每周清單**](https://www.techinterviewhandbook.org/coding-interview-study-plan/) #### 2. [**Blind 75**](https://leetcode.com/discuss/general-discussion/460599/blind-75-leetcode-questions) ## 資料結構 #### 1. 基礎需知 - Linked List vs Array - Linked List 新增、刪除節點須熟練 | | 優點 | 缺點 | | -------- | -------- | -------- | | Linked List | 動態配置、彈性,刪除新增節點快 | 需額外空間儲存指向下一個節點的指標 | | Array | 隨機存取容易,sorting後用sorting方便 | 新增刪除不易 | - Queue vs Stack - Queue : - FIFO - BFS用 - Stack : - FILO - DFS用 - Heap - Max Heap vs Min Heap - Heap Sort - Tree - 需會操作: - traversal : preorder, inorder, postorder - BST : insert, delete, search - 需知道的terms: - BST - Balanced Binary Tree - Complete Binary Tree - Red-Black Tree | Binary Tree | Complete Binary Tree | Balanced Binary Tree | | -------- | -------- | -------- | | ![](https://i.imgur.com/p33zVJv.png) | ![](https://i.imgur.com/7dHVTOI.png)| ![](https://i.imgur.com/ZcyNq34.png)| | 最多有兩個節點 | 除了最後一層都有nodes,且僅右子樹可以有缺 | 節點左右子樹高度差不超過1 | - [Graph](https://www.techinterviewhandbook.org/algorithms/graph/) - 需會操作: - BFS, DFS, topological sort #### 2. C++ STL - map | 區別 | ordered_map | unordered_map | |:-------------:|:-----------:|:-----------------------------:| | 有順序性(key) | 有 | 無 | | 實作方法 | 紅黑樹 | 雜湊表 | | Search | $log(n)$ | $O(1)$-Average, $O(n)$-Worst | | Insert | $log(n)$ | $O(1)$-Average, $O(n)$-Worst | | Delete | $log(n)$ | $O(1)$-Average, $O(n)$-Worst | - set - same as map - priority_queue - 不同於queue,以**max heap**實作,預設**從大排到小**,top為最大元素。 - 有n個資料欲插入排序情況下,複雜度與**heap sort**皆為$O(nlogn)$。 - 需 `#include <queue>` | Operation | Find max/min | Insert |Remove |Heapify (create a heap out of given array of elements)| | -------- | -------- | -------- |-------- |-------- | | Big-O | $O(1)$ | $O(log(n))$ |$O(log(n))$ |$O(n)$ | ## 演算法 - Sorting | 演算法 | Best | Worst |Worst/Best Case情況| Avg | 空間複雜度 | 穩定性 | 類型 | | --------------------------- |:------------:| ----------------------- | ---------------- | ----------------- | ------ | ---- |---- | | 選擇排序法(Selection Sort) | Ο($n^2$) | Ο($n^2$) |一直都須全部跑過一次比較 | Ο($n^2$) | Ο(1) | 不穩定 | 比較選擇後交換 | | 插入排序法(Insertion Sort) | Ο($n$) | Ο($n^2$) | (best)輸入是排序過的數列 | Ο($n^2$) | Ο(1) | 穩定 | 比較後插入 | | 氣泡排序法(Bubble Sort) | Ο($n$) | Ο($n^2$) |(best)輸入是排序過的數列 | Ο($n^2$) | Ο(1) | 穩定 | 左右比較後交換 | |~~謝爾排序法(Shell Sort)~~ | Ο($n$) | Ο($n^2$)~ Ο($n^1$$^.5$) |-| Ο($n^5$$^/$$^4$) | Ο($n$) + Ο(1) | 不穩定 | 插入 | | ~~搖晃排序法(Shaker Sort)~~ | Ο($n$) | Ο($n^2$) | -|Ο($n^2$) | Ο(1) | 穩定 | 交換 | | **快速排序法(Quick Sort)** | Ο($n log n$) | Ο($n^2$) |(best)pivot剛好是中位數/ \(worst)輸入排序過的數列| Ο($n log n$) | Ο($log n$)~Ο($n$) | 不穩定 | 交換 | | **合併排序法(Merge Sort)** | Ο($n log n$) | Ο($n log n$) |一直都須全部跑過一次比較| Ο($n log n$) | Ο($n$) | 穩定 | 合併 | | **堆積排序法(Heap Sort)** | Ο($n log n$) | Ο($n log n$) |? | Ο($n log n$) | $MaxHeapTree$ Ο($n$) + $Inplace$ Ο(1) | 不穩定 | 選擇 | | **計數排序(Counting Sort)** | Ο($n+k$) | Ο($n+k$) |k較大 / k較小| Ο($n+k$) | Ο($n+k$) | 穩定 | 計數(非比較型) | | **基數排序(Radix Sort)** | Ο($d×(n+k)$) | Ο($d×(n+r)$) |?| Ο($d×(n+k)$) -LSD | Ο($n+k$) | 穩定 | 每個digit是用counting sort比 | - Searching - Binary Search - String - [KMP](https://medium.com/nlp-tsupei/kmp%E7%AE%97%E6%B3%95%E8%A9%B3%E8%A7%A3-1b1050a45850) (Knuth–Morris–Pratt ) | 方法 | 比對字串(搜尋) |說明| | -------- | -------- | -------- | | 爆破法 | $O(mn)$ |遍歷尋找| | Knuth–Morris–Pratt | $O(m+n)$ |建立failure_function: $O(m)$, 比對過程: $O(n)$| - Min Path in Graph - [Dijkstra Algorithm](https://medium.com/%E6%8A%80%E8%A1%93%E7%AD%86%E8%A8%98/%E5%9F%BA%E7%A4%8E%E6%BC%94%E7%AE%97%E6%B3%95%E7%B3%BB%E5%88%97-graph-%E8%B3%87%E6%96%99%E7%B5%90%E6%A7%8B%E8%88%87dijkstras-algorithm-6134f62c1fc2) ## C++課程 #### 1. [線上課程](http://ocw.nctu.edu.tw/course_detail-v.php?bgid=9&gid=0&nid=412&v5=0J2eLvkuF8k) #### 2. 經典問題 - 1. virtual function是什麼? - 2. override, overwrite, overload? - 3. 繼承的建構、解構順序 - 4. OOP三大概念 - 封裝 - 繼承 - 多型 ## 面試經驗分享 ### 1. 群聯 - 面試職位: - 軟韌體1601 - 韌體03 #### C 面試考題範圍 [快速看一遍](https://mycollegenotebook.medium.com/c-%E8%AA%9E%E8%A8%80%E7%B5%B1%E6%95%B4%E7%AD%86%E8%A8%98-f97326e2323c) - 基礎I/O: - Input: ``` int num; scanf("%d",&num);` ``` - Output: ``` int num = 10; printf("this apple costs %d dollars.",num);` ``` - 資料型別大小: ![](https://i.imgur.com/WdrydQU.png) - float - [小數怎算](https://hackmd.io/@A7mW1DtZSiuuCn3Bh0KIjQ/B1S5MvGsw) - [如何表示float](https://dotblogs.com.tw/daniel/2018/11/10/161148) - ![](https://i.imgur.com/razhflk.png) - sign: 1位 - exponent: 8位 - mantissa: 23位 - 精準度: $2^{23}$~ $10^{3^{2.3}}$ ~$10^{6.9}$: 保證6位(6~7位) - 表示值:$正數最大:10^{38}$,正數最小$10^{-38}$ - double - sign: 1位 - exponent: 11位 - mantissa: 52位 - 精準度: $2^{52}$ ~ $10^{3^{5.2}}$ ~ $10^{15.6}$: 保證15位(15~16位) - 表示值: $正數最大:10^{308}$,正數最小$10^{-308}$ - #### Little Endian/ Big Endian ![](https://hackmd.io/_uploads/Bye93RwNn.png) ![reference link](https://hackmd.io/_uploads/rJO5nCwE3.png) ``` #include <stdio.h> typedef union { unsigned long l; unsigned char c[4]; } EndianTest; int main() { EndianTest et; et.l = 0x12345678; printf("本系統位元組順序為:"); if (et.c[0] == 0x78 && et.c[1] == 0x56 && et.c[2] == 0x34 && et.c[3] == 0x12) { printf("Little Endiann"); } else if (et.c[0] == 0x12 && et.c[1] == 0x34 && et.c[2] == 0x56 && et.c[3] == 0x78) { printf("Big Endian"); } else { printf("Unknown Endian"); } printf("0x%lX 在記憶體中的儲存順序:n", et.l); for (int i = 0; i < 4; i++) { printf("%p : 0x%02Xn", &et.c[i], et.c[i]); } return 0; } ``` - #### bitwise operation - [SET,CLEAR,CHECK,FLIP BITS](http://j890111tw.blogspot.com/2019/10/bitwise-operation.html) - #### 確認是否為2的次方 - 2的倍數共通點:**n & (n-1) = 0** - ex. 2 & 1 = 10 & 01 = 00 - #### 一個array裡面除了某一個數字以外,其他數字都出現2次,請找尋出現一次的數字? - **xor : 兩個bit不同才回傳1,相同回傳0** - 1100 xor 1100 = 0000 - 1100 xor 1100 xor 1001 = 0000 xor 1001 = 1001 - **以0000去xor所有數字,最後ans = 只出現一次的數字** - #### 找尋第n個bit的數字: - **& mask with only bit n = 1** - ex. 0001 1001 , get bit 5: - ((0001 1001) & (0001 0000)) >> 4 = (0001 0000) >> 4 = 1 - ((op_bits) & $2^{n-1}$) >> (n-1) = (opbits >> (n-1)) & 1 - #### 確認是偶數或奇數: - 奇數共通點: 第一個bit($2^0$)為1 - **return n & 1 ==1 ? odd result : even result;** - ex. 0011 & 0001 = 0001 - #### Basic Operation - #### 重要須知:set、clear、flip bits時,默認最右邊最低位bit的索引編號為0;但是在講取得第5個bit的值時,是假設右邊最低位bit為第1個bit;須明辨! - setbit(int x, int bitN): 用or ``` int setbit(int x, int bitN) { x = (x | 1<<bitN); return x; } ``` - clearbit(int x, int bitN): 用 not 跟 and ``` int clearbit(int x, int bitN) { x &= ~(1<<bitN); return x; } ``` - **flipbit(int x, int n)/reversebit: 把bit翻成相反值: 用xor** ``` int flipbit(int x, int n) { x ^= (1<<bitN); return x; } ``` - **getbit(int x, int n) : 用 and: 注意index從0** ``` int flipbit(int x, int n) { x = (x >>(bitN)) & 1; return x; } ``` - #### string operation - 宣告:就算不設陣列大小也是可以宣告字串 ``` char str1[ 6 ] = "hello"; char str2[] = "starbucks"; // size 10 //一般的陣列宣告也適用,只是要注意會多一項‘\0’ char str3[ 6 ] = {'h', 'e', 'l', 'l', '0', '\0'}; char str4[] = {'s', 't', 'a', 'r', 'b', 'u', 'c', 'k', 's','\0'}; ``` - 輸入: 字串儲存方式本身即為一個char陣列,輸入不須用&指位址,本身就是位址。 `scanf("%s %d", name, &age);` - scanf: 遇到空格就結束 - gets: 遇到換行才結束(但用法不安全,即不確定多少個字元才會結束) - fgets: 指定最多幾個char結束,輸入的字串會自動加入換行符號 `fgets(字串開頭位址s,輸入字元數20,輸入方式stdin)` - sscanf: 讀取字串,並把字串中的值依照要求個別放入不同變數 ``` char weather[100] = "cloudy 20"; int tp; char s[100]; sscanf(weather,"%s %d",s,&d); printf("the day is %s, temperature is %d.\n",s,d); ``` - 輸出: - printf - fputs `fputs(字串開頭位置s,輸出方式stdout)` - sprintf: 整合輸出到一個字串(含輸出+整合) ``` char weather[100]; int tp = 20; char* s = "cloudy"; sprintf(weather,"the temperature is %d, the day is %s.",tp,s); printf("the weather is %s.\n",weather); ``` - <string.h> - strlen(char* s) : 得到字串長度,不計終止符號'\0' ``` #include <stdio.h> int strlen_implement(char * s) { int count = 0; while(*(s+count)!='\0') { count++; } return count; } ``` - strcmp(char* s1, char* s2):從字串的開始逐一比對兩字串的字元是否相同 ``` #include <stdio.h> #include <string.h> int strcmp_implement(char* s1, char* s2) { while(*s1==*s2) { if (*s1 == '\0' || *s2 == '\0') break; s1++; s2++; } return (*s1-*s2); } ``` - strncmp(char* s1, char* s2, int n):從字串的開始逐一比對,兩字串**前n個字元**是否相同 ``` #include <stdio.h> #include <string.h> int strncmp_implement(char* s1, char* s2, int n) { int count = 0; while(*s1==*s2 && count < n) { if (*s1 == '\0' || *s2 == '\0') break; s1++; s2++; count++; } return (*s1-*s2); } ``` - strcat(char* dest, char* src):把source字串加在目標字串上 ``` #include <stdio.h> #include <string.h> void strcat_implement(char* s1, char* s2) { //s1,s2 are copy of address //change position didn't influence the pointer in the main fucntion char* tmp = s1; while (*tmp!='\0') { tmp++; } while (*s2 != '\0') { *tmp = *s2; tmp++; s2++; } *tmp = '\0'; } ``` - strncat(char* s1, char* s2, int n): 把s2前n個character加到s1上。 ``` #include <stdio.h> #include <string.h> void strcat_implement(char* s1, char* s2, int n) { int count = 0; char* tmp = s1; while (*tmp!='\0') { tmp++; } while (*s2 != '\0' && n > count) { *tmp = *s2; tmp++; s2++; count++; } *tmp = '\0'; } ``` - strcpy(char* s1, char* s2):把s2複製到s1上 ``` #include <stdio.h> #include <string.h> void strcpy(char* s1, char* s2) { while(*s2!='\0') { *s1 = *s2; s1++; s2++; } *s1 = '\0'; return; } ``` - strncpy(char* s1, char* s2, int n):把s2前n個字元複製到s1上 ``` #include <stdio.h> #include <string.h> void strncpy(char* s1, char* s2, int n) { int count = 0; while(*s2!='\0' && count < n) { *s1 = *s2; s1++; s2++; count++; } *s1 = '\0'; return; } ``` - 字串數字轉換: `include <stdlib.h>` - atoi(char* s) : 字串轉成int - atof(char* s) : 字串轉成float - atol(char* s) : 字串轉成long - #### structures - 自訂義資料型態,可儲存多種資料型態 ``` struct student { char name[30]; int age; }; //ver 1 : initialize struct student s1 ; struct student s2 ; //ver 2 : initialize s1 = (struct student) {"Aliee",25}; //ver 3 : initialize struct student s2 = {"Kevin",30}; ``` - **typedef** : 減輕需要很長的宣告與使用 ``` typedef struct { char name[30]; int age; }student; //ver 1 : initialize student s1 ; student s2 ; //ver 2 : initialize s1 = (student) {"Aliee",25}; //ver 3 : initialize student s2 = {"Kevin",30}; ``` - struct pointer: ``` typedef struct { char name[20]; int age; }student; void show(student* s) { prinft("The student %s is %d years old.\n",s->name,s->age); } student s1 = {"Willy",28}; student s2 = {"Lisa",27}; show(&s1); show(&s2) ``` - #### extern 和 static? - extern: 引用外部的全域變數;ex.在a.cpp定義的全域變數,可在b.cpp當中透過extern方法來引用。(但引用的變數不可為static。) - static: 變數存在的時間與主程式一樣長,但作用域不變,ex.寫在function內的變數仍只能在該function中使用。如果用在類別當中的變數或函式上,該static的變數和函式不屬於任何一個物件,為該類別共用的。 - #### const(還有分前後順序,請參考新思的考古) - #### ???????????????? - #### pointer operation - [簡單說明](https://mycollegenotebook.medium.com/c%E8%AA%9E%E8%A8%80%E7%AD%86%E8%A8%98-%E6%8C%87%E6%A8%99-pointers-d28edcdd6283) - btw, nullptr僅C++有 - 記憶體位址(16進制):0xFFFFFFFF : $2^{32} bytes=4GB$ - **較大重點:** - 對於陣列 a = {1,2,3,4,5}; - **&a : 指的是整個陣列的位址**, &a+1 會走到下一個相鄰未定義的記憶體區塊 - **a : 指的是陣列的開頭位址**, a+1 會走到陣列裡下一個位址,在這裡即下一個整數。 ``` int a = {1,2,3,4,5}; int* ptr = (int*)(&a + 1); printf("ptr-1 = %d",*(ptr-1)); //output: 4 int b = {1,2,3,4,5}; int p = (int*) (b+1); printf("p-1 = %d",*(p-1)); //output: 1 ``` - #### function/ array of function pointer - function pointer : 指向函式的pointer,**指標處一定要括號** ``` //宣告函式pointer void checkAccess(int num){return num >= 1;}; void (*funcptr) (int); //output_t (*pointer_name) (input_t) funcptr = checkAccess; // assign函式指標 int n = 0; printf("enter the access number=>\n"); scanf("%d",&n); funcptr(n); //實際使用function ``` - array function pointer : 幫助減少if-else等流程控制 ``` #include <stdio.h> int add(int num1, int num2); //宣告加法函式 int subtract(int num1, int num2); //宣告減法函式 int multiply(int num1, int num2); //宣告乘法函式 int divide(int num1, int num2); //宣告除法函式 //宣告函式指標陣列 int (*op[4]) (int,int); op[0] = add; // assign函式指標 op[1] = subtract; // assign函式指標 op[2] = multiply; // assign函式指標 op[3] = divide; // assign函式指標 int choice = 3; op[choice](0,1); //實際使用function ``` - #### array reverse || string reverse - 頭尾交換,直到中間。 ``` void swap(int* a1, int* a2) { int tmp = *a1; *a1 = *a2; *a2 = tmp; return; } void reverse_arr(int* a, int m) { if (m<=1) return; for(int i = 0; i < m/2 ; i++) { swap(a[i],a[m-i-1]); } return; } ``` - #### linked list - linked list insert ``` struct ListNode { int val; ListNode* next; ListNode(int x): val(x), next(NULL){}; }; class LinkedList { public: void insert(ListNode* prev, ListNode* add) { ListNode* nxt = prev->next; prev->next = add; add->next = nxt; } void insert(ListNode* prev, int v) { ListNode* nxt = prev->next; prev->next = new ListNode(v); prev->next->next = nxt; } private: ListNode* head = NULL; }; ``` - linked list 實作 queue ``` struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL){}; }; class Queue { public: bool isEmpty() { if (head==NULL) return true; else return false; } int front() { if (!isEmpty()) return head->val; else return NULL; } void push(int x) { if (isEmpty()) { head = end = new ListNode(x); } else { end->next = new ListNode(x); end = end->next; } return; } int back() { if (!isEmpty()) { return end->val; } else { return NULL; } } void pop() { if (!isEmpty()) { ListNode* nxt = head->next; delete head; head = nxt; } return; } private: ListNode* head = NULL; ListNode* end = NULL; }; ``` - #### shuffle the array ``` #include<stdio.h> #include<stdlib.h> #include<time.h> void shuffle(int *array, size_t n){ //亂數前置 srand(time(NULL)); if (n > 1){ size_t i; for (int i = n-1; i >= 0; i--){ size_t j = rand() % (i+1); int t = array[j]; array[j] = array[i]; array[i] = t; } } } ``` - #### compile / linker / runtime error? - **compiler error**: 編譯時發生的錯誤,可能是像是語法錯誤造成的 - **linker error**: 要把不同的object file連結在一起時發生的問題,可以確認是否有正確include其他object file。(或是不同object file裡面使用到同名的全局變量也可能造成這個問題,static可解決:static僅在當前文件可見->也是為什麼不能用在extern的原因。) - **runtime error**: 在執行時才發生的錯誤,例如除法分母為0的情況 - #### union/struct/class sizeof()計算與對齊方法? - struct vs class: - class預設成員為private,struct預設成員為pulic。 - class有繼承、多型等應用,但struct沒有。 - union vs struct: - union 和 struct 都可以儲存不同型態。 - union 同時只有一個類別的值可以儲存。union大小為最長的那個型態且可以整除該union最長基本儲存型態;可以節省記憶體空間;而struct則是可以同時儲存多項,故比較佔記憶體。 - union 宣告上基本上長的和struct相同,只差把關鍵字換成union: ``` union student { int x; char hi; float height; }; ``` - sizeof()/對齊問題: - union: 該union內**最長的數據長度**,但要**對齊最長基本類型長度** ``` union u { double a; //最長數據=8,同時為最長基本類型->不用對齊 int b; }; union u2 { char a[13]; //最長的數據=13 int b; //最長的基本類型長度4 }; union u3 { char a[13]; //最長的數據=13 char b; //最長的基本類型長度1->不用對齊 }; printf("sizeof(u) = %d.\n",sizeof(u)); // 8 printf("sizeof(u) = %d.\n",sizeof(u2)); // 16 printf("sizeof(u) = %d.\n",sizeof(u3)); // 13 ``` - struct: 以struct內**下一個類別的長度來對齊**,最後**總長度要對整個struct內最長的基礎類型補齊**。 ``` structA { inta; // 4 shortb; // (4) + 2 = 6 下一元素爲 int,需對齊爲 4 的倍數, 6 + (2) = 8 intc; // (8) + 4 = (12) char d; // (12) + 1 = 13, 需補齊爲 4 的倍數,13 + (3) = 16 }; structB { inta; // 4 shortb; // (4) + 2 = 6,下一成員爲 char 類型,不考慮對齊 char c; // (6) + 1 = 7,下一成員爲 int 類型,需對其爲 4 的倍數,7 + (1) = 8 intd; // (8) + 4 = 12,已是 4 的倍數 } union C //24字節:20對齊8 { int a[5]; //20 short b; // 2 double c; //8 char p2; //1 }; struct D { int n; // 4字節 +(4):union C 最長基礎類型8 C c; // 4 + (4) +24字節 char c[10]; // 4 + (4) + 24 +10 + (6) = 48字節 }; ``` - 可以用**pragma back(size)** 設定編譯時對齊的長度,C++基本上取對界大小跟最長成員長度兩者中**較小**的那個。 - #### 面試流程 - 1601 - 主管 - HR - 03 - 工程師 - 小主管 - 大主管 - HR > 面試經驗不佳,細節可以問我XD ### 2. 台積 - #### 面試職位: - IT - #### 需準備的: - 自我介紹 - 專案須熟悉 - 如有docker, k8s, CICD概念佳 - 如有資料庫專案經驗可能會問 - #### 面試流程: - codility - 主管面試 - HR面試 - 適性測驗/英文測驗(五年內多益700up免測) ### 3. 新思 - #### 面試職位: - Software RD Engineer - #### 需準備的: - 英文自我介紹 - C++ - 基本面試問題 - #### 面試流程 * DAY-1 : 104丟履歷 * DAY-5 : HR電話簡單訪談 * DAY-13: 部門主管電話簡單說明工作內容、給codility * DAY-17: 寫完codility * DAY-24: 主管面談、寫C++考卷 * DAY-31: 兩位工程師技術面談 * DAY-34: 口頭offer * DAY-38: 書面offer