###### Agenda: ###### 11/30 10:00(UTC+8) 11/29 19:00(UTC-7) ###### 公布這次live session題目 ###### 11/30 10:45(UTC+8) 11/29 19:45(UTC-7) ###### 開始逐步給hint ###### 11/30 11:30(UTC+8) 11/29 20:30(UTC-7) ###### 題解 + Q&A ###### 還沒有加入DC伺服器的請記得加入,並去查看#學員驗證頻道進行驗證才可以看到live session的討論區https://discord.gg/WUE3XutPK3 --- ### 本周題目 ### LeetCode weekly contest 394 ### https://leetcode.com/contest/weekly-contest-394/ ### 中文題目 ### https://leetcode.cn/contest/weekly-contest-394/ --- ### Hint - Q1 : - ##### hint 1: 想一下如何判斷當下的字母是大寫還是小寫 ---- ### Hint - Q1 - ##### hint 1: 想一下如何判斷當下的字母是大寫還是小寫 - ##### hint 2: 最多只有26個不同的字母(不管大小寫) ---- ### Hint - Q1 - ##### hint 1: 想一下如何判斷當下的字母是大寫還是小寫 - ##### hint 2: 最多只有26個不同的字母(不管大小寫) - ##### hint 3: 每個字母判斷一下有沒有出現過大小寫 --- ### Hint - Q2: - ##### hint 1: 考慮只有一個字母時,他符合答案應該要長什麼樣子 ---- ### Hint - Q2: - ##### hint 1: 考慮只有一個字母時,他符合答案應該要長什麼樣子 - ##### hint 2: 列一下不符合答案的狀態有幾種 ---- ### Hint - Q2: - ##### hint 1: 考慮只有一個字母時,他符合答案應該要長什麼樣子 - ##### hint 2: 列一下不符合答案的狀態有幾種 - ##### hint 3: 若出現小寫後又出現大寫則不符合答案 --- ### Hint - Q3 - ##### hint 1: 題目轉換後,其實是我們想讓同一個column 的數字相同,且相鄰 column 的數字不一樣 ---- ### Hint - Q3 - ##### hint 1: 題目轉換後,其實是我們想讓同一個column 的數字相同,且相鄰 column 的數字不一樣 - ##### hint 2: 其實對於一個 column 來說,我們只在意每個數字出現了幾次 ---- ### Hint - Q3 - ##### hint 1: 題目轉換後,其實是我們想讓同一個column 的數字相同,且相鄰 column 的數字不一樣 - ##### hint 2: 其實對於一個 column 來說,我們只在意每個數字出現了幾次 - ##### hint 3: 想像我們從第一個 column 開始填,對於之後每個 column ,我們只在意前一個 column 填了甚麼數字 ---- ### Hint - Q3 - ##### hint 1: 題目轉換後,其實是我們想讓同一個column 的數字相同,且相鄰 column 的數字不一樣 - ##### hint 2: 其實對於一個column來說,我們只在意每個數字出現了幾次 - ##### hint 3: 想像我們從第一個column開始填,對於之後每個column,我們只在意前一個column填了甚麼數字 - ##### hint 4: 每一個column只需要跟前後兩個column比對,因此只需要考慮前三大出現的數字 --- ### Hint - Q4 - ##### hint 1: 先算出0->n-1的最短路 ---- ### Hint - Q4 - ##### hint 1: 先算出0->n-1的最短路 - ##### hint 2: 在算出最短路時,其實0到每個點的最短路都被算出來了 ---- ### Hint - Q4 - ##### hint 1: 先算出0~n-1的最短路 - ##### hint 2: 在算出最短路時,其實0到每個點的最短路都被算出來了 - ##### hint 3: 一條路連接(x,y)有沒有在0~n-1最短路裡面其實可以嘗試硬走到這條路 ---- ### Hint - Q4 - ##### hint 1: 先算出0~n-1的最短路 - ##### hint 2: 在算出最短路時,其實0到每個點的最短路都被算出來了 - ##### hint 3: 一條路連接(x,y)有沒有在0~n-1最短路裡面其實可以嘗試硬走到這條路 - ##### hint 4: 硬走的意思其實是就從 0 走到 x 再從 x 走這條路到 y 再從 y 走到 n-1 ---- ### Hint - Q4 - ##### hint 1: 先算出0~n-1的最短路 - ##### hint 2: 在算出最短路時,其實0到每個點的最短路都被算出來了 - ##### hint 3: 一條路連接(x,y)有沒有在0~n-1最短路裡面其實可以嘗試硬走到這條路 - ##### hint 4: 硬走的意思其實是就從 0 走到 x 再從 x 走這條路到 y 再從 y 走到 n-1 - ##### hint 5: 從 y 走到 n-1 這段資料還沒有,是不是有辦法也預先處理出來 --- ### 題解 ---- ### Q1 題目 - 給一個字串,問有幾個字母的大寫及小寫都在字串裡面出現過 ---- ### Q1 - 使用一個26長度的array,去紀錄每個字母的出現情況 - 每格array可以再使用一個長度為2的array ---- ### Q1 c++ ```c++ //time complexity: O(n) //Extra space complexity: O(1) int numberOfSpecialChars(string word) { int vis[26][2]; memset(vis, 0, sizeof(vis)); for (auto it : word) { if (it >= 'a' && it <= 'z') { vis[it - 'a'][0] = 1; } else { vis[it - 'A'][1] = 1; } } int ans = 0; for (int i = 0; i < 26; i++) { if (vis[i][0] && vis[i][1]) { ans++; } } return ans; } ``` ---- ### Test case - 字母只出現大寫 - 字母只出現小寫 - 字母大小寫都出現 - "AaBc" ---- ### Q2 題目 - 給一個字串,問有幾個字母的大寫及小寫都在字串裡面出現過 - 但如果該字母的所有小寫需要出現在第一個大寫前 ---- ### Q2 - 考慮一個字母,他應該會長成這樣 - "aaaaAAAA" - 所以跟Q1一樣紀錄大小寫,但在記錄小寫的時候,額外判斷前面是否出現過大寫了 ---- ```c++ //time complexity: O(n) //Extra space complexity: O(1) int numberOfSpecialChars(string word) { int vis[26][3]; memset(vis, 0, sizeof(vis)); for (auto it : word) { if (it >= 'a' && it <= 'z') { vis[it - 'a'][0] = 1; if (vis[it - 'a'][1]) { vis[it - 'a'][2] = 1; } } else { vis[it - 'A'][1] = 1; } } int ans = 0; for (int i = 0; i < 26; i++) { if (vis[i][0] && vis[i][1] && !vis[i][2]) { ans++; } } return ans; } ``` ---- ### Test case - 跟Q1 類似 - 額外檢查在Q2會不被視為答案的測資 - "Aa" - "aAa" ---- ### Q3 題目 - 給一個grid,每一格為一個0~9的數字,每次操作可以更換一格的數字 - 求最少操作次數使得同一個column數字相同,相鄰的column數字不相同 ---- ### Q3 題目 - 合法狀態 ![image](https://hackmd.io/_uploads/BkFUnZdWWe.png) - 不合法狀態 ![image](https://hackmd.io/_uploads/H1zF3ZdZWl.png) ---- ### Q3 - 假設我們從第一個column開始填,因為可以從前一個column的狀態得到現在的答案因此想使用dp - 定義dp狀態 dp[i][j] = 前i個column後面且第i個column使用j這個數字時,需要更改幾個數字(or 有幾個數字不用被更改) ---- ### Q3 - 因為每個column只考慮前三高頻率出現的數字的 所以我們可以轉換一下讓j變成第j高頻率出現的數字 - 轉移就是 dp[i][j] = dp[i-1][k] + 第i column第j高頻率出現數字的次數 且只有在j跟k代表數字不相同時才能轉移 ---- ### Q3 處理出前三大出現次數 ```c++ //time complexity: O(n*m) //Extra space complexity: O(m) vector<vector<int>> dp(grid[0].size(), vector<int>(3)); vector<vector<pair<int, int>>> numberCnt(grid[0].size()); for (int i = 0; i < grid[0].size(); i++) { int cnt[10]; fill(cnt, cnt + 10, 0); for (int j = 0; j < grid.size(); j++) { cnt[grid[j][i]]++; } for (int j = 0; j < 10; j++) { numberCnt[i].push_back(make_pair(cnt[j], j)); } sort(numberCnt[i].begin(), numberCnt[i].end()); reverse(numberCnt[i].begin(), numberCnt[i].end()); } ``` ---- ### Q3 更新 dp 狀態 ```c++ for (int i = 0; i < 3; i++) { dp[0][i] = numberCnt[0][i].first; } for (int i = 1; i < grid[0].size(); i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { if (numberCnt[i][j].second != numberCnt[i - 1][k].second) { dp[i][j] = max(dp[i][j], dp[i - 1][k] + numberCnt[i][j].first); } } } } int ans = 0; for (int i = 0; i < 3; i++) { ans = max(ans, dp[grid[0].size() - 1][i]); } return grid.size() * grid[0].size() - ans; ``` ---- ### Test case - 要用到第三高頻率出現的數字 - [1,1,2] - [1,1,2] - [1,2,2] - [1,2,2] - [1,3,2] - 一個column - 一個row - 會有兩邊相同數字的 - [1,1,1] - [1,0,1] ---- ### Q4 題目 - 給定一個無向的 graph ,對於每一個 edge ,想確認是否有一條0->n-1的最短路徑會走經過這條edge ---- ### Q4 題目 - ![image](https://hackmd.io/_uploads/rynrVGu-Wx.png) ---- ### Q4 - 看到hint 4,我們把一條路徑切成 0->x x->y y->n-1,若這條路徑長度與0->n-1相同,代表x y可以作為每條最短路徑的一部分 - 0->x 可以用0走最短路徑得到所有答案 - y->n-1 其實也可以用n-1走最短路徑得到所有答案 - 用0跟n-1去做最短路徑,接下來拿每條路徑嘗試一次就可以了 ---- ### Q4 最短路徑 ``` c++ //time complexity: O((n+m) log m) //Extra space complexity: O(m) vector<int> shortestPath(int n, int start, vector<vector<pair<int, int>>> v) { priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(0, start)); vector<int> dis(n, -1); while (!pq.empty()) { auto p = pq.top(); pq.pop(); if (dis[p.second] != -1) { continue; } dis[p.second] = p.first; for (auto it : v[p.second]) { if (dis[it.first] == -1) { pq.push(make_pair(p.first + it.second, it.first)); } } } return dis; } ``` ---- ### Q4 main ``` c++ vector<bool> findAnswer(int n, vector<vector<int>>& edges) { vector<vector<pair<int, int>>> v(n); for (auto it : edges) { v[it[0]].push_back(make_pair(it[1], it[2])); v[it[1]].push_back(make_pair(it[0], it[2])); } auto dis1 = shortestPath(n, 0, v); auto dis2 = shortestPath(n, n - 1, v); vector<bool> res; for (auto it : edges) { if (dis1[n - 1] == -1 || dis1[it[0]] == -1 || dis1[it[1]] == -1) { res.push_back(false); } else if (dis1[it[0]] + dis2[it[1]] + it[2] == dis1[n - 1]) { res.push_back(true); } else if (dis1[it[1]] + dis2[it[0]] + it[2] == dis1[n - 1]) { res.push_back(true); } else { res.push_back(false); } } return res; } ``` ---- ### Test case - 0到不了 n - 1 - 有些路徑到不了 n - 1 - ![image](https://hackmd.io/_uploads/SyA_8GdZWe.png) - 所有edge都可以是最短路徑的一部分 --- ### 幫我們填寫一下回饋表單讓我們變得更好 - https://forms.gle/U995TPnVEiEziyjm9 ![image](https://hackmd.io/_uploads/HJh2_fOb-e.png)
{"title":"1130 live session","description":"Q1 :","contributors":"[{\"id\":\"214a576a-9d94-453a-a11d-248251d46d4e\",\"add\":12488,\"del\":4446,\"latestUpdatedAt\":1764475326444}]"}
    112 views