---
title: 2021 年資訊科技產業專案設計課程面試範例
tags: INFO2021
---
# 2021 年「[資訊科技產業專案設計]
> 貢獻者: 勞孰-Mouse
> ==[video](https://youtu.be/AXq38zDe_vw)==
## 英語影片題目
### [977. Squares of a Sorted Array](https://leetcode.com/problems/squares-of-a-sorted-array/)
* 直觀想法: 走訪 input array 並 squares 每個 element,然後再針對新元素進行排序。
* Time complexity: 因為需要排序,所以是 O(nlogn)
```cpp=
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for (int i{0}; i<nums.size(); ++i) {
nums[i] = nums[i]*nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
```
* 改進方法: 考慮以下兩點,可使用 2 pointers 技巧實做 O(n) 的演算法。
1. input elements 已經是 sorted 的狀態
2. given two integer a and b, 有 $|a| > |b| -> a^2 > b^2$
因此我們可以使用 two pointers
1. 剛開始分別指向 the most negetive element 和 the most positive element
2. 比較此二 element 誰的絕對值較大,將較大者的平方從頭插入 output array,並將其 pointer 向內移動一格
3. 如果兩個指標已經交叉,中止並回傳結果。否則回到 2.
```cpp=
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int l = 0;
int r = nums.size() - 1;
vector<int> res;
while (l <= r) {
if (abs(nums[l]) > abs(nums[r])) {
res.push_back(nums[l]*nums[l]);
l++;
} else {
res.push_back(nums[r]*nums[r]);
r--;
}
}
reverse(res.begin(), res.end());
return res;
}
};
```
### [278. First Bad Version](https://leetcode.com/problems/first-bad-version/)
* 直覺想法: 從第一個 version 開始,線性搜尋至發現第一個 bad version
* Time complexity: O(n)
* 此法在 leetcode 提交得到 TLE
```cpp=
// The API isBadVersion is defined for you.
// bool isBadVersion(int version);
class Solution {
public:
int firstBadVersion(int n) {
int i = 1;
for (; i <= n; ++i) {
if (isBadVersion(i))
break;
}
return i;
}
};
```
* 改進方法: 考慮到小於 first bad version 之所有版本皆為 not bad; 而大於等於 first bad version 之所有版本皆為 bad version。我們可以用 binary search 找出產品由 good version 轉為 bad version 的分界點
* Time complexity: O(logn)
```cpp=
class Solution {
public:
int firstBadVersion(int n) {
long long l = 1;
long long r = (long long)n;
long long m = 0;
while (l <= r) {
m = (l + r) >> 1;
if (isBadVersion(m) == true) {
r = m - 1;
} else {
l = m + 1;
}
}
return (int)l;
}
};
```
### [34. Find First and Last Position of Element in Sorted Array (HW2)](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/)
* 想法 1: linear search 找到 target element 的開頭以及結束位址
* 想法 2: 考慮到 element 已經 sorted,可以使用 binary search 找到其中一個 target value (若有多個以上,找到任一個即可)。隨後從這個 element 往兩邊的 index probe 開頭/結束位址。
* 想法 3: 原問題可以理解成要找出兩個目標位置,即由左至右
* 第一次出現 target element 的位置
* 第一次出現 > target element 的位置 - 1
-> 所以此問題可以使用兩次的 binary search 解決:
```cpp=
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
return {findFirst(nums, target), findLast(nums, target)};
}
private:
int findFirst(vector<int>& nums, int target)
{
int l = 0;
int r = nums.size()-1;
while (l <= r) {
int m = (l+r)/2;
if (nums[m] >= target) {
r = m - 1;
} else {
l = m + 1;
}
}
if (l == nums.size() || nums[l] != target)
return -1;
return l;
}
int findLast(vector<int>& nums, int target)
{
int l = 0;
int r = nums.size()-1;
while (l <= r) {
int m = (l+r)/2;
if (nums[m] > target) {
r = m - 1;
} else {
l = m + 1;
}
}
l--;
if (l < 0 || nums[l] != target)
return -1;
return l;
}
};
```
### [695. Max Area of Island](https://leetcode.com/problems/max-area-of-island/)
* 想法: iterate over input matrix 的每一個 cell,一旦碰到一個 1 (land),就執行一次 DFS (從一個 cell 出發可能走的方向有四個方向) 已計算出包含此 cell 的 island 大小。計算出所有 island 大小後回傳最大者。
* Time complexity: O((mn)^2)
* 此法會重複計算同一島嶼多次,在 leetcode 提交得到 stack overflow
```cpp=
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
m = grid.size();
n = grid[0].size();
int curMax = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j])
curMax = max(curMax, findMax(grid, i ,j));
}
}
return curMax;
}
private:
int m, n;
int findMax(vector<vector<int>>& grid, int i, int j)
{
if (i < 0 || i >= m || j < 0 || j >= n)
return 0;
if (grid[i][j] == 0)
return 0;
return 1 + findMax(grid, i+1, j) + findMax(grid, i, j+1) + findMax(grid, i-1, j) + findMax(grid, i, j-1);
}
};
```
* 改進空間: 對原本的遞迴進行剪枝,將已經走訪過的 cell 設為 0。這樣可以讓同一個 island 不會被重複計算多次。
* Time complexity: O(mn)
```diff=
class Solution {
public:
int maxAreaOfIsland(vector<vector<int>>& grid) {
m = grid.size();
n = grid[0].size();
int curMax = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j])
curMax = max(curMax, findMax(grid, i ,j));
}
}
return curMax;
}
private:
int m, n;
int findMax(vector<vector<int>>& grid, int i, int j)
{
if (i < 0 || i >= m || j < 0 || j >= n)
return 0;
if (grid[i][j] == 0)
return 0;
+ grid[i][j] = 0;
return 1 + findMax(grid, i+1, j) + findMax(grid, i, j+1) + findMax(grid, i-1, j) + findMax(grid, i, j-1);
}
};
```
## 漢語影片題目
### [242. Valid Anagram](https://leetcode.com/problems/valid-anagram/)
* 想法1: 對兩個字串分別 sorting,然後比對 sorted 字串是否完全相同
* Time complexxity: O(nlogn)
```cpp=
class Solution {
public:
bool isAnagram(string s, string t) {
sort(s.begin(), s.end());
sort(t.begin(), t.end());
if(s.compare(t) == 0){
return true;
}
return false;
}
};
```
* 想法2: 利用一個 array 記下某一字串的各字元出現次數 (字串只會有 lower case letter-> O(1) space 成本),再拿此 array 與另一個字串之各字元次數比對。
* Time complexxity: O(n)
```cpp=
class Solution {
public:
bool isAnagram(string s, string t) {
vector<int> hashMap(26, 0);
for (auto c : s) {
hashMap[c-'a']++;
}
for (auto c : t) {
hashMap[c-'a']--;
}
for (int i = 0 ; i < 26; ++i) {
if (hashMap[i] != 0)
return false;
}
return true;
}
};
```
### [198. House Robber](https://leetcode.com/problems/house-robber/)
* 想法: 遞迴。
首先給定遞迴函式 f(n) 之邊界條件:
(1) 如果只有一間房子,則最大可搶的錢為這間房子內的錢。f(1) = nums[0]
(2) 如果有兩間房子,因為同時不能搶相鄰的房子,選錢多的房子。f(2) = max(nums[0], nums[1])
接著,考慮第 n 間房子,如果
(1) 我們搶了第 n 間房子,則不能搶第 n-1 間房子。可搶到的錢為 nums[n] + f(n-2)
(2) 我們不搶第 n 間房子。可搶到的錢為 f(n-1)
另外,為了不重複計算遞迴,我們利用 recursion with memorization (top down dp) 記下算過的值。
```cpp=
class Solution {
public:
vector<int> dp;
int rob(vector<int>& nums) {
int len = nums.size();
if (len == 1)
return nums[0];
for (int i = 0; i < len; ++i)
dp.push_back(-1);
dp[0] = nums[0];
dp[1] = max(nums[0], nums[1]);
return rec(len-1, nums);
}
private:
int rec(int n, vector<int>& nums)
{
if (dp[n] != -1)
return dp[n];
dp[n] = max(rec(n-2, nums) + nums[n], rec(n-1, nums));
return dp[n];
}
};
```
### [11. Container With Most Water](https://leetcode.com/problems/container-with-most-water/)
* 想法1: 對任二個牆壁計算他們所形成的容器大小,並記下最大者
* Time complexity: O(n^2)
* 想法2: 基於以下觀察
對於兩個容器 a 和 b,如果 a 的寬度比 b 小,則有
$若a 的容量比 b 大,則 a 較低的牆較 b 較低的牆高$
由上敘述,則可知其實不用每種組合都算一次,我們只需算"可能可以得到更多水量的組合"。我們可利用 two pointers 技巧,分別指向最左,最右的牆壁,即從最寬的容器開始算。每次算完一種組合後,將指向較低的牆壁向內 (往另一個指標方向) 移動一格。(因為若移動較高的牆壁,新容器的高度仍為原較低的牆)
```cpp=
class Solution {
public:
int maxArea(vector<int>& height) {
int l = 0;
int r = height.size()-1;
int maxWater = INT_MIN;
while (l < r) {
maxWater = max(maxWater, (r-l)*min(height[l], height[r]));
if (height[l] > height[r])
r--;
else
l++;
}
return maxWater;
}
};
```
## 第三次作業 - 他評
### Interviewee
#### 優點
- 在第一個題目的coding之前,有和interviewer進行良好的溝通,並更明確的確定題目的限制及邊界。
- 在approach階段有清楚說明方法,並且可以同時coding讓interviewer更進入coding的現狀。
#### 可改進
- 在[4:40](https://youtu.be/AXq38zDe_vw&t=280s),interviewer表示希望時間複雜度在linear的時候,應該簡單介紹原本的時間複雜度之後盡快進入下一種方法,以免再interviewer不期望的approach上耗費時間。
- [11:40](https://youtu.be/AXq38zDe_vw&t=700s),在進階問題的時候,有重新描述一次題目,但少了和intertviewer討論問題的環節。
- 在coding完之後,應該做一些簡單的驗證來證明自己的code。
### Interviewer
- 在進階問題的階段,應該做多一點討論,而不是interviewer自己coding然後就草草結束。
## 第三次作業 - 他評 2
### Interviewer
### 優點
* 題目講解的很清楚
* 有與面試者進行討論
### 缺點
* 第一個題目空間複雜度為 linear time 的優化解法完成後,沒有其他的評論就進到下一題了
* 第二題都是 interviewee 一直講, interviewer 缺乏互動
### Interviewee
### 優點
* 有完整 REACO 且有詢問題目的一些可能的限制條件
* 完整分析程式碼的時間複雜度,也有考慮到空間複雜度且優化
* 有完整解釋 hash_table 的使用
### 缺點
* [10:59](https://youtu.be/AXq38zDe_vw?t=659) 這邊寫完後可以加入 Test,舉個 Example 來驗證自己的程式碼
* [13:08](https://youtu.be/AXq38zDe_vw?t=788) 可以說因為有 $C_{n}^{2}$ 種可能,所以會是 string 個數的平方
* [19:39](https://youtu.be/AXq38zDe_vw?t=1179) 第二題解完後沒有任何的 Test 去驗證程式碼的正確性,也解釋時間複雜度的部分
## 第三次作業 - 他評 3
### Interviewer
### 優點
* 有清楚的描述題目需求,且 Interviewee 對第一個問題提出問題時有明確定義邊界與內容
### 缺點
* [4:33](https://youtu.be/AXq38zDe_vw?t=272) Interviewer 可以先問 Interviewee 會採用的 Sorting 演算法時間複雜等級為多少,再提出須要更快的方法
* [11:11](https://youtu.be/AXq38zDe_vw?t=662)不用明確表達要進到第二個問題,可直接給一個簡單的例子和 Interviewee 討論
### Interviewee
### 優點
* 第一題時有和 Interviewer 討論是否會有其他狀況發生
* 兩題都有做到 REAC,並且花在 Example 的時間不算太長
### 缺點
* Interviewee 完成題目時沒有做 Test 和 Optimization
## 第三次作業 - 他評 4
* [8:19](https://youtu.be/AXq38zDe_vw?t=499) 宣告已知大小的陣列時建議使用 `std::array<T, N>` 或 `T[N]`
* [16:17](https://youtu.be/AXq38zDe_vw?t=977) 變數命名應避免[與 std 衝突](https://en.cppreference.com/w/cpp/utility/hash)
* 第二題沒有兩方互動
## 第三次作業 - 他評 5
### Interviewer
### 優點
* 題目講解清楚
* 第一題有與 interviewee 做互動且給予回饋
### 缺點
* [4:35](https://youtu.be/AXq38zDe_vw?t=275) 「對演算法做優化或是加速」這句話可以改成 「時間上的優化」比較好
### Interviewee
### 優點
* 有做到 REACO,也有先詢問邊界和 constraint
* 有舉出例子和解說
### 缺點
* [13:06](https://youtu.be/AXq38zDe_vw?t=786) 這裡分析時間複雜度時花費的時間有點久,前面已經有說明了需要兩兩配對做比較,那只需要告訴 interviewer 其時間複雜度為 $O(n^2)$ ,字串長度為常數,不需要計算進去
* 沒有做 test
## 第三次作業 - 他評 6
### Interviewer
#### 優點:
* 不是以背題目的方式來說明題目。
* 題目設計第一題和第二題有連貫。
#### 可改進:
* 第二題的互動可以再多一點。
### Interviewee
#### 優點:
* 有完整做到 REACO。
* 口語表達流暢清晰。
#### 可改進:
* 可以做簡單的 Test 驗證自己的 Code。
# 第三次作業-他評7
> * 題目敘述完整,且清楚表達要求
> * 互動過程中有舉例及解釋,也有討論的行為
> * 選題有相關
## interviewer
* [00:15](https://youtu.be/AXq38zDe_vw?t=15) 解釋題目的時候很像在背題目,解釋題目時避開一些特定名詞可以避免interviewee背答案
## interviewee
* [1:00](https://youtu.be/AXq38zDe_vw?t=59) 馬賽克不見了@@
* [1:52](https://youtu.be/AXq38zDe_vw?t=111) 字有點小,看不太清楚