# 2023 年「[資訊科技產業專案設計](https://hackmd.io/@sysprog/info2023)」作業 1
> [模擬面試錄影-1](https://youtu.be/tzNY52QwA2I)
> [模擬面試錄影-2](https://youtu.be/ND10VCttwr0)
>
> :male-office-worker: Interviewer;:male-student: Interviewee
## [1929. Concatenation of Array](https://leetcode.com/problems/concatenation-of-array/description/)
> [Google Docs](https://docs.google.com/document/d/1WPAYD8GsYkbdKQz_5Dhquhm-7BndPBphClPTCsgV5Ec/edit?usp=sharing)
### Interview
:male-office-worker:第一題給你一個長度為 n 的 array **nums**,需要你寫一個 function 回傳長度為 2n 的 array **ans**。而這個 ans 就是兩份 nums (copy & paste)
:male-student:問題是希望我們 return 一個 array ans,而這個 ans 會剛好是 nums copy 成兩份,像範例 nums=[1,2,1], ans=[1,2,1,1,2,1]。
:male-student:我會先宣告 ans,並使其長度設為 nums 的兩倍,然後再用迴圈給值。
:male-office-worker: 聽起來可行,那你就試試看吧。
```cpp
vector<int> buildArray(vector<int>& nums) {
vector<int>ans;
ans.resize(2*num.size());
for(int i=0;i<num.size()*2;i++){
ans[i] = nums[i];
}
return ans;
}
```
:male-office-worker: 請你對這份程式碼做時間複雜度和空間複雜度,並想想看有甚麼可以優化的地方。
:male-student: 由於 ans 是固定為 2n,所以空間複雜度的 lower bound 在 O(2N),而現在這段迴圈跑 2 倍的 nums 的長度,所以時間複雜度是 O(2N)。
:male-student: 可以優化的地方是由於前半和後半是一樣的,所以其實跑一次 0~n 就可以了:
```cpp
vector<int> buildArray(vector<int>& nums) {
vector<int>ans;
ans.resize(2*num.size());
for(int i=0;i<num.size();i++){
ans[i] = nums[i];
ans[i+n] = nums[i];
}
return ans;
}
```
## [2807. Insert Greatest Common Divisors in Linked List](https://leetcode.com/problems/insert-greatest-common-divisors-in-linked-list/description/)
> [Google Docs](https://docs.google.com/document/d/1duiN9X6JcX5gabproYIYnXQLCx-mixgsfgioNsf9kTg/edit?usp=sharing)
### Interview
:male-office-worker: 第二題是給你一個整數的 Linked List,希望你寫一個 function 為每兩個節點之間加上每兩個節點的值的最大公因數,最後回傳加上最大公因數的 Linked List。
:male-student: 首先,我會先設好結束的條件,也就是當**現在節點**指向 null 並且**下一個節點指向** null,那就不會繼續接下來的操作。
:male-student: 接著,找出**現在節點**和**下一個節點**的最大公因數,並以此為值創建一個新的節點,並將這幾個節點的next做調整,讓其各自指向正確的節點。
:male-office-worker: 聽起來可行,那你就試著做做看吧。
```cpp
ListNode* FindGCD(int v1, int v2){
while(v1!=0 && v2!=0){
if(v1>v2){
v1%=v2;
}
else{
v2%=v1;
}
}
ListNode* newNode;
if(v1>v2){
newNode = new ListNode(v1);
}
else{
newNode = new ListNode(v2);
}
return newNode;
};
ListNode* insertGreatestCommonDivisors(ListNode* head) {
ListNode * tmp = head;
while(tmp != null && tmp->next !=null){
ListNode* insertNode = FindGCD(tmp->val, tmp->next->val);
insertNode->next = tmp->next;
tmp->next = insertNode;
tmp = insertNode->next;
}
return head;
}
```
## [1920. Build Array from Permutation](https://leetcode.com/problems/build-array-from-permutation/description/)
> [Google Docs](https://docs.google.com/document/d/15xaw8lonx8upmPM8j5Nzj0LeRzKRlu0w56Ha-Ckl3eo/edit?usp=sharing)
### Interview
:male-office-worker: Give you a integer array **nums**,build an array ans of the same length where ans[i] = nums[nums[i]] for each 0 <= i < nums.length and return it。
:male-student: So, First i would create an array ans, and then go through it from 0~n. For each iteration just imply ans[i] = nums[nums[i]];
```cpp
vector<int> buildArray(vector<int>& nums) {
vector<int> ans;
int n = nums.size();
ans.resize(n);
for(int i=0;i<n;i++){
ans[i] = nums[nums[i]];
}
return ans;
}
```
:male-office-worker: I noticed that you used out-place implementation,can you give another approach using in-plcae implementation?
:male-student: In-place implementation: we can let nums[i] become ```(length of nums)*NewValue (nums[nums[i]]) + OriValue (nums[i])``` , then divide it by length of nums. So, nums[i] would be ```(length of nums)*NewValue/(length of nums)```=NewValue(nums[nums[i]])
```cpp
vector<int> buildArray(vector<int>& nums) {
int n = nums.size();
for(int i=0;i<n;i++){
nums[i] = nums[nums[i]]*n + nums[i];
}
for(int i=0;i<n;i++){
num[i]/=n;
}
return nums;
}
```
## 初步檢討
* 程式邏輯可以再解釋清楚一點。
* 說話可以清楚一點、大聲一點(但會吵到室友),咬蠻多字的。
* 避免冗言贅字和過多的語助詞。
* 專有科技名詞會中英文混著使用。
* 英文會中途跑出中文,需加強練習英文說明的部分。
* 思考的過程會習慣性沉默,應該可以分享當時任何想法。
---
## 第二次作業 - 他評 01
**Interviewer**
優點
- 有先確認雙方是否都有聽到聲音
- 沒有出現上對下的名詞,整個面試氣氛良好。
可改進處
- 建議可以針對程式碼做進一步的討論,例如:
- [2:44](https://youtu.be/tzNY52QwA2I?si=FGdlJjS_HH1H--EC&t=164): 為什麼不直接宣告 2n 的大小,而是要使用 resize。
- [6:31](https://youtu.be/tzNY52QwA2I?si=YNiChciMR78I9OPx&t=391): 面試者修改後實際上存取的次數依舊是 2n 次,但這樣寫帶來的好處是什麼?(參考:[Loop Unrolling](https://en.wikipedia.org/wiki/Loop_unrolling))
- (英) 建議把題目敘述一遍給面試者聽,增加雙方互動。
- (英) [7:36](https://youtu.be/ND10VCttwr0?si=vOm-uKv9p8LgiNDG&t=456): 建議使用討論的方式取代直接告訴面試者存在更佳解。例如:有沒有辦法使用更少的空間。
**Interviewee**
優點
- 有一邊寫一遍進行講解。
可改進處
- [1:06](https://youtu.be/tzNY52QwA2I?si=4k2MrCFHhWWcegGf&t=66): REACTO 中 Repeat 步驟感覺像是在告訴面試官題目,建議更改複誦方式,讓其聽起來更像是在跟面試官確認題意。
- [4:04](https://youtu.be/tzNY52QwA2I?si=olWKS5oG4k5mrJAs&t=244): 影片提到「index 的因素考慮進去」,建議可以直接講考慮的因素,例如:存取到非法記憶體。
- (英) [8:18](https://youtu.be/ND10VCttwr0?si=I__AFmOYX5H4CSh6&t=498): 建議可以更清楚的交代思考的邏輯,而非直接寫出答案。
其他建議
- [11:54](https://youtu.be/tzNY52QwA2I?si=vSbaw4sRdmIy_Q-T&t=714): 不確定翻書是否是可以的,建議可以先與面試官討論。
## 第二次作業 - 他評 02
- [ ] 優點
* 聽下來都說明得很流暢,沒有什麼比較突兀的停頓感
* 在 Appoarch 階段有明確說出自己的想法,並把想法直接列在文件中
* 第二題 [11:37](https://youtu.be/tzNY52QwA2I): 不急著把 `FindGCD()` 實作出來,而是留到後面才實作
- [ ] 可改進之處
* 第二題 [11:37](https://youtu.be/tzNY52QwA2I): `FindGCD()` 可以參考下列的寫法,就可以減去比較 `v1` 與 `v2` 大小的時間
```cpp
ListNode* FindGCD(int v1, int v2){
// 這裡會自動處理 v1 < v2 的狀況,讓後續保證 v1 > v2
while(v2 != 0){
int temp = v2;
v2 = v1 % v2;
v1 = temp;
}
ListNode* newNode = new ListNode(v1);
return newNode;
};
```
* 第二題 [17:47](https://youtu.be/tzNY52QwA2I): Testing 時建議可以把過程一樣打在文件中,怕單純用口述的會讓 Interviewer 不好理解
* 第三題 [6:12](https://youtu.be/ND10VCttwr0): 可以把 `i=0, nums[0] = 0, nums[0] = 0` 寫為 `i=0, nums[0] = 0, nums[nums[0]] = 0` 會更為清楚
## 第二次作業 - 他評03
### interviewer
- [ ] 優點
* 語速把控得當
* 咬字清晰
* 有雙向互動
- [ ] 可改進的地方
* 說話有點卡詞
* 有些段落氣音太重
### interviewee
- [ ] 優點
* 有完整做出REACTO
* 編寫程式碼時有做清楚的講解
* 手勢和肢體動作增加表達強度
- [ ] 可改進的地方
* 收音有點模糊