666.路径和IV
题目链接:666.路径和IV
解法:
参考这篇题解:【LeetCode - 666】路径和 IV_力扣666路径总和4-CSDN博客
关键点在于:
(1)使用map来存node:key 为整数的前两位,value 为整数的后一位,即 key 为位置信息,value 为权值,KV是(num / 10, num % 10);
(2)左右子树的表示:对于某一个节点来说,如果它的深度为depth,位置编号为 pos,那么它的左子节点的深度为depth+1,位置编号为 pos × 2 - 1,那么key就是 (depth+1) * 10 + pos*2-1。而它的右子节点的pos和key都是左子节点的加1;
(3)如果左子节点和右子节点均不在 map 中,说明一条路径计算完毕,ans += sum;
(4)如果两个子节点中有一个不在map中,那么dfs会直接对该子节点return,否则继续dfs。
边界条件:左子树或者右子树为空。
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {int ans = 0;// 使用unordered_map,插入、删除和查找的平均时间复杂度为O(1)// 而map是有序的,这三种操作为O(logn)unordered_map<int,int> map;public:int pathSum(vector<int>& nums) {for (int num: nums) {map[num / 10] = num % 10;}dfs(nums[0]/10, 0);return ans;}private:void dfs(int node, int sum) {auto it = map.find(node);if (it == map.end()) {return;}sum += it->second;int depth = node / 10;int pos = node % 10;int left = (depth + 1) * 10 + pos * 2 - 1;int right = left + 1;if (map.find(left)==map.end() && map.find(right)==map.end()) {ans += sum;} else {dfs(left, sum);dfs(right, sum);}}
};
207.课程表
题目链接:207.course-schedule
解法:
两种解法,bfs和dfs。
bfs:需要提前计算所有课的入度和先修课的邻接表,入度为0的课意味着没有任何先修课,可以先选。剩下的看题解,这篇题解写得很好:bfs题解。
代码的实现参考这篇题解:bfs代码
dfs:在构造邻接表时,有的答案是把先修课作为vector的索引或者map的key,也有的把先修课作为vector的元素。这里按前一种,把先修课作为vector的索引,得从先修课开始选,根据先修课再去遍历以它为前置条件的课程,直到搜索到某门课不是任何课程的先修课,说明从当前课开始dfs的路径,是有限无环的。
以下题解来自eetcode中文区:dfs代码
边界条件:
时间复杂度 O(N+M): 遍历一个图需要访问所有节点和所有临边,N 和 M分别为节点数量和临边数量;
空间复杂度 O(N+M): 为建立邻接表所需额外空间,adjacency 长度为 N ,并存储 M条临边的数据。
// bfs
class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> adjacency(numCourses);vector<int> indegrees(numCourses, 0);queue<int> que;for (const auto& cp:prerequisites) {adjacency[cp[1]].push_back(cp[0]);indegrees[cp[0]]++;}for (int i=0; i<numCourses; i++) {if (indegrees[i]==0) que.push(i);}while (!que.empty()) {int pre = que.front();que.pop();numCourses--;for (int cur: adjacency[pre]) {indegrees[cur]--;if (indegrees[cur]==0) que.push(cur);}}return numCourses == 0;}
};
// dfs
class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> adjacency(numCourses);vector<int> flags(numCourses, 0);for (const auto& cp:prerequisites) {adjacency[cp[1]].push_back(cp[0]);}for (int i=0; i<numCourses; i++) {if (!dfs(adjacency, flags, i)) return false;}return true;}private:bool dfs(const vector<vector<int>>& adjacency, vector<int>& flags, int i) {if (flags[i] == 1) return false;if (flags[i] == -1) return true;flags[i] = 1;for (int j: adjacency[i]) {if (!dfs(adjacency, flags, j)) return false;}flags[i] = -1;return true;}
};
210. 课程表||
题目链接:210.course-schedule-ii
解法:
与207几乎一样,代码改动量很小。如果不先做207,那几乎是搞不懂的。
dfs改动大一些,result需要翻转一下,因为先修课是最后才加入列表的。
边界条件:
时间复杂度:同207
空间复杂度:同207
// bfs
class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> adjacency(numCourses);vector<int> indegrees(numCourses, 0);queue<int> que;vector<int> result;for (const auto& cp:prerequisites) {adjacency[cp[1]].push_back(cp[0]);indegrees[cp[0]]++;}for (int i=0; i<numCourses; i++) {if (indegrees[i]==0) que.push(i);}while (!que.empty()) {int pre = que.front();que.pop();result.push_back(pre);for (int cur: adjacency[pre]) {indegrees[cur]--;if (indegrees[cur]==0) que.push(cur);}}if (result.size()!=numCourses) return {};return result;}
};
// dfs
class Solution {vector<int> result;public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> adjacency(numCourses);vector<int> flags(numCourses, 0);for (const auto& cp:prerequisites) {adjacency[cp[1]].push_back(cp[0]);}for (int i=0; i<numCourses; i++) {if (!dfs(adjacency, flags, i)) return {};}// 要翻转reverse(result.begin(), result.end());return result;}private:bool dfs(const vector<vector<int>>& adjacency, vector<int>& flags, int i) {if (flags[i] == 1) return false;if (flags[i] == -1) return true;flags[i] = 1;for (int j: adjacency[i]) {if (!dfs(adjacency, flags, j)) return false;}flags[i] = -1;result.push_back(i);return true;}
};