置頂

我的 VPython 教學文件 (HackMD 版本)

VPython 教學文件目錄 安裝及測試 基本語法 等速度直線運動 自由落下 終端速度 水平抛射 使用For迴圈計算水平抛射資料 斜向抛射 圓周運動 簡諧運動 單擺 木塊彈簧系統分離 重力及簡諧 行星運動 相疊木塊 雙重簡諧運動 一維彈性碰撞 ...

熱門文章

2026年8月5日 星期三

LeetCode 解題筆記:3310. Remove Methods From Project

作者:王一哲
日期:2026年8月5日


LeetCode 題目連結:3310. Remove Methods From Project

解題想法


中等難度題。對我而言,這題最大的困難在於看懂題目的意思。題目給一個計畫的方法之間先後順序的關係,方法數量為 $n$,編號為 $0$ 到 $n-1$,其中編號 $k$ 是可疑的方法,$k$ 之後的方法都被視為可疑的方法;但如果有這群可疑方法之外沒有問題的方法指向這個群組,則整群可疑的方法都不能被移除;最後要回傳剩下的方法。可以將這些方法視為有向圖的節點,先用 BFS 或 DFS 從節點 $k$ 出發,將 $k$ 及相連的節點都標記為可疑。再用一個 for 迴圈掃過所有節點,如果節點 $u$ 是沒有問題的節點,而且 $u$ 指向任何一個可疑的節點,則所有節點都不能被移除。如果需要移除可疑的節點,只回傳沒有問題的節點;反之,回傳所有節點。

Python 程式碼


BFS. Runtime: 227 ms, beats 90.15%. Memory: 99.66 MB, beats 89.39%.
class Solution:
    def remainingMethods(self, n: int, k: int, invocations: List[List[int]]) -> List[int]:
        # 用接鄰矩陣儲存下一個相關的方法
        adj = [[] for _ in range(n)]
        for u, v in invocations:
            adj[u].append(v)
        
        # 用 BFS 標記可疑的方法
        suspicious = [False] * n
        que = deque([k])
        while que:
            u = que.popleft()
            suspicious[u] = True
            for v in adj[u]:
                if not suspicious[v]:
                    que.append(v)
        
        # 檢查是否有外部可用的方法呼叫任何可疑的方法,如果有,不能移除任何可疑的方法
        removed = True
        for u in range(n):
            if not suspicious[u]:
                for v in adj[u]:
                    if suspicious[v]:
                        removed = False
                        break
        
        # 回傳答案,如果需要移除可疑的方法,只回傳可用的方法
        if removed:
            return [i for i in range(n) if not suspicious[i]]
        else:  # 反之,不能移除任何方法,回傳全部的方法
            return list(range(n))


DFS. Runtime: 271 ms, beats 76.51%. Memory: 144.79 MB, beats 36.36%.
class Solution:
    def remainingMethods(self, n: int, k: int, invocations: List[List[int]]) -> List[int]:
        # 用接鄰矩陣儲存下一個相關的方法
        adj = [[] for _ in range(n)]
        for u, v in invocations:
            adj[u].append(v)
        
        # 用 DFS 標記可疑的方法
        suspicious = [False] * n
        
        def dfs(u):
            suspicious[u] = True
            for v in adj[u]:
                if not suspicious[v]:
                    dfs(v)
        
        dfs(k)  # 呼叫 dfs,從方法 k 開始遍歷

        # 檢查是否有外部可用的方法呼叫任何可疑的方法,如果有,不能移除任何可疑的方法
        removed = True
        for u in range(n):
            if not suspicious[u]:
                for v in adj[u]:
                    if suspicious[v]:
                        removed = False
                        break
        
        # 回傳答案,如果需要移除可疑的方法,只回傳可用的方法
        if removed:
            return [i for i in range(n) if not suspicious[i]]
        else:  # 反之,不能移除任何方法,回傳全部的方法
            return list(range(n))


C++ 程式碼


BFS. Runtime: 323 ms, beats 39.66%. Memory: 331.55 MB, beats 42.07%.
class Solution {
public:
    vector<int> remainingMethods(int n, int k, vector<vector<int>>& invocations) {
        // 用接鄰矩陣儲存下一個相關的方法
        vector<vector<int>> adj (n);
        for(auto it : invocations) {
            adj[it[0]].push_back(it[1]);
        }
        
        // 用 BFS 標記可疑的方法
        vector<bool> suspicious (n, false);
        queue<int> que;
        que.push(k);
        while(!que.empty()) {
            int u = que.front();
            que.pop();
            suspicious[u] = true;
            for(int v : adj[u]) {
                if (!suspicious[v]) {
                    que.push(v);
                }
            }
        }

        // 檢查是否有外部可用的方法呼叫任何可疑的方法,如果有,不能移除任何可疑的方法
        bool removed = true;
        for(int u = 0; u < n; u++) {
            if (!suspicious[u]) {
                for(int v : adj[u]) {
                    if (suspicious[v]) {
                        removed = false;
                        break;
                    }
                }
            }
        }
        
        // 回傳答案,如果需要移除可疑的方法,只回傳可用的方法
        vector<int> ans;
        if (removed) {
            for(int i = 0; i < n; i++) {
                if (!suspicious[i]) {
                    ans.push_back(i);
                }
            }
        } else {  // 反之,不能移除任何方法,回傳全部的方法
            ans.resize(n);
            iota(ans.begin(), ans.end(), 0);
        }
        return ans;
    }
};


DFS. Runtime: 333 ms, beats 36.60%. Memory: 336.62 MB, beats 40.00%.
class Solution {
public:
    vector<vector<int>> adj;
    vector<bool> suspicious;
    
    void dfs(int u) {
        suspicious[u] = true;
        for(int v : adj[u]) {
            if (!suspicious[v]) {
                dfs(v);
            }
        }
    }        

    vector<int> remainingMethods(int n, int k, vector<vector<int>>& invocations) {
        // 用接鄰矩陣儲存下一個相關的方法
        adj.clear();
        adj.resize(n);
        for(auto it : invocations) {
            adj[it[0]].push_back(it[1]);
        }
        
        // 用 DFS 標記可疑的方法
        suspicious.assign(n, false);
        dfs(k);  // 呼叫 dfs,從方法 k 開始遍歷

        // 檢查是否有外部可用的方法呼叫任何可疑的方法,如果有,不能移除任何可疑的方法
        bool removed = true;
        for(int u = 0; u < n; u++) {
            if (!suspicious[u]) {
                for(int v : adj[u]) {
                    if (suspicious[v]) {
                        removed = false;
                        break;
                    }
                }
            }
        }
        
        // 回傳答案,如果需要移除可疑的方法,只回傳可用的方法
        vector<int> ans;
        if (removed) {
            for(int i = 0; i < n; i++) {
                if (!suspicious[i]) {
                    ans.push_back(i);
                }
            }
        } else {  // 反之,不能移除任何方法,回傳全部的方法
            ans.resize(n);
            iota(ans.begin(), ans.end(), 0);
        }
        return ans;
    }
};


沒有留言:

張貼留言