【101】Symmetric Tree node
判斷一棵樹是否是對稱。算法
題解:直接遞歸判斷了,感受和bfs沒有什麼強聯繫,固然若是你必定要用queue改寫的話,勉強也能算bfs。數組
// 這個題目的重點是 比較對象是 左子樹的左兒子和右子樹的右兒子, 左子樹的右兒子和右子樹的左兒子。不要搞錯。數據結構
// 直接中序遍歷的話會有錯的狀況,最蠢的狀況是數字標註改一改。。app
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 // 這個題目的重點是 比較對象是 左子樹的左兒子和右子樹的右兒子, 左子樹的右兒子和右子樹的左兒子。不要搞錯。 11 // 直接中序遍歷的話會有錯的狀況,最蠢的狀況是數字標註改一改。。 12 class Solution { 13 public: 14 bool isSymmetric(TreeNode* left, TreeNode* right) { 15 if (left == NULL && right == NULL) {return true;} 16 if (left == NULL || right == NULL) {return false;} 17 return (left->val == right->val) && isSymmetric(left->left, right->right) && isSymmetric(left->right, right->left); 18 } 19 bool isSymmetric(TreeNode* root) { 20 if (!root) { 21 return true; 22 } 23 return isSymmetric(root->left, root->right); 24 } 25 };
【102】Binary Tree Level Order Traversal ide
二叉樹的層級遍歷。函數
題解:兩個隊列直接遍歷。ui
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<vector<int>> levelOrder(TreeNode* root) { 13 vector<vector<int>> ans; 14 if (!root) { 15 return ans; 16 } 17 queue<TreeNode*> que1, que2; 18 que1.push(root); 19 while (!que1.empty()) { 20 vector<int> temp; 21 while (!que1.empty()) { 22 TreeNode* node = que1.front(); 23 que1.pop(); 24 temp.push_back(node->val); 25 if (node->left) { 26 que2.push(node->left); 27 } 28 if (node->right) { 29 que2.push(node->right); 30 } 31 } 32 ans.push_back(temp); 33 temp.clear(); 34 swap(que1, que2); 35 } 36 return ans; 37 } 38 };
【103】Binary Tree Zigzag Level Order Traversal this
二叉樹的蛇形層級遍歷。spa
題解:我是直接用了兩個棧,固然,也能夠直接層級遍歷出結果真後reverse。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<vector<int>> zigzagLevelOrder(TreeNode* root) { 13 vector<vector<int>> ans; 14 if (!root) {return ans;} 15 stack<TreeNode*> st1, st2; 16 st1.push(root); 17 bool reverse = true; 18 while (!st1.empty()) { 19 vector<int> temp; 20 while (!st1.empty()) { 21 TreeNode* node = st1.top(); 22 st1.pop(); 23 temp.push_back(node->val); 24 if (reverse) { 25 if (node->left) { 26 st2.push(node->left); 27 } 28 if (node->right) { 29 st2.push(node->right); 30 } 31 } else { 32 if (node->right) { 33 st2.push(node->right); 34 } 35 if (node->left) { 36 st2.push(node->left); 37 } 38 } 39 } 40 ans.push_back(temp); 41 temp.clear(); 42 swap(st1, st2); 43 reverse = 1 - reverse; 44 } 45 return ans; 46 } 47 };
【107】Binary Tree Level Order Traversal II
二叉樹從下往上的層級遍歷
題解:我直接把層級遍歷reverse了一下。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<vector<int>> levelOrderBottom(TreeNode* root) { 13 vector<vector<int>> ans; 14 if (!root) { 15 return ans; 16 } 17 queue<TreeNode*> que1, que2; 18 que1.push(root); 19 while (!que1.empty()) { 20 vector<int> temp; 21 while (!que1.empty()) { 22 TreeNode* node = que1.front(); 23 que1.pop(); 24 temp.push_back(node->val); 25 if (node->left) { 26 que2.push(node->left); 27 } 28 if (node->right) { 29 que2.push(node->right); 30 } 31 } 32 ans.push_back(temp); 33 temp.clear(); 34 swap(que1, que2); 35 } 36 reverse(ans.begin(), ans.end()); 37 return ans; 38 } 39 };
【111】Minimum Depth of Binary Tree
返回一棵二叉樹的最短的高度,最短的高度的定義是從根開始到沒有左右兒子的葉子節點的最短的距離。
題解:直接bfs,判斷出葉子節點就中止。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 int minDepth(TreeNode* root) { 13 int ans = 0; 14 if (!root) {return ans;} 15 queue<TreeNode*> que, que2; 16 que.push(root); 17 bool finish = false; 18 while (!que.empty()) { 19 while (!que.empty()) { 20 TreeNode* node = que.front(); 21 que.pop(); 22 if (node == NULL) {continue;} 23 if (node->left == NULL && node->right == NULL) { 24 finish = true; 25 break; 26 } else { 27 que2.push(node->left); 28 que2.push(node->right); 29 } 30 } 31 ans++; 32 if (finish) { 33 break; 34 } 35 swap(que, que2); 36 } 37 return ans; 38 } 39 };
【126】Word Ladder II
題目和127題同樣,區別在於這題要求返回所有最短路徑。
題解:修改了一下127題的題解,在bfs的時候增長一個層次數組,把每層走過的單詞都存起來,一旦找到了目標單詞,回溯整個層級數組獲得答案。
1 class Solution { 2 public: 3 bool distance1(string& s, string& t) { 4 int n = s.size(); 5 int dis = 0; 6 for (int i = 0; i < n; ++i) { 7 if (s[i] != t[i]) { 8 ++dis; 9 } 10 if (dis >= 2) { return false; } 11 } 12 return dis == 1 ? true : false; 13 } 14 void dfs(vector<vector<string>>& ans, vector<string>& temp, string curWord, int level) { 15 if (temp.back() == beginW) { 16 ans.push_back(temp); 17 } 18 if (level == wordLevel.size()) { return; } 19 vector<string> list = wordLevel[level]; 20 for (auto word : list) { 21 if (distance1(word, curWord)) { 22 temp.push_back(word); 23 dfs(ans, temp, word, level+1); 24 temp.pop_back(); 25 } 26 } 27 } 28 vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) { 29 vector<vector<string>> ans; 30 if (find(wordList.begin(), wordList.end(), endWord) == wordList.end()) {return ans;} 31 queue<string> que, que2; 32 set<string> st; 33 que.push(beginWord); 34 bool findAns = false; 35 while(!que.empty()) { 36 vector<string> temp; 37 while (!que.empty()) { 38 string str = que.front(); 39 temp.push_back(str); 40 que.pop(); 41 for (auto word : wordList) { 42 if (distance1(str, word) && st.find(word) == st.end()) { 43 if (word == endWord) { 44 findAns = true; 45 } 46 que2.push(word); 47 st.insert(word); 48 } 49 } 50 } 51 wordLevel.push_back(temp); 52 if (findAns) { 53 break; 54 } 55 swap(que, que2); 56 } 57 /* 58 printf("findAns = %d\n", findAns); 59 for (int i = 0; i < wordLevel.size(); ++i) { 60 for (int j = 0; j < wordLevel[j].size(); ++j) { 61 cout << wordLevel[i][j] << ""; 62 } 63 cout << endl; 64 } 65 */ 66 if (findAns == false) { return ans; } 67 reverse(wordLevel.begin(), wordLevel.end()); 68 beginW = beginWord, endW = endWord; 69 vector<string> temp; 70 temp.push_back(endW); 71 dfs(ans, temp, endW, 0); 72 for (int i = 0; i < ans.size(); ++i) { 73 reverse(ans[i].begin(), ans[i].end()); 74 } 75 return ans; 76 } 77 string beginW, endW; 78 vector<vector<string>> wordLevel; 79 };
【127】Word Ladder (2018年12月28日,第一次複習,ko)
給了一個初始單詞和一個目標單詞和一個單詞字典,每次變換隻能把當前單詞變一個字母變成單詞字典裏面的一個詞,問初始單詞通過幾回變換能變成目標單詞。
題解:從初始單詞開始,從字典裏面找到能走一步的全部的單詞放到隊列裏,而後遍歷隊列,直到找到目標單詞,注意字典中全部的單詞只能用一次,否則可能有環,就死循環了。
1 class Solution { 2 public: 3 bool distance1(string& s, string& t) { 4 int n = s.size(); 5 int dis = 0; 6 for (int i = 0; i < n; ++i) { 7 if (s[i] != t[i]) { 8 ++dis; 9 } 10 if (dis >= 2) { return false; } 11 } 12 return dis == 1 ? true : false; 13 } 14 15 int ladderLength(string beginWord, string endWord, vector<string>& wordList) { 16 int ans = 0; 17 if (find(wordList.begin(), wordList.end(), endWord) == wordList.end()) {return ans;} 18 queue<string> que, que2; 19 set<string> st; 20 que.push(beginWord); 21 ans = 1; 22 bool findAns = false; 23 while(!que.empty()) { 24 while (!que.empty()) { 25 string str = que.front(); 26 que.pop(); 27 for (auto word : wordList) { 28 if (distance1(str, word) && st.find(word) == st.end()) { 29 if (word == endWord) { 30 findAns = true; 31 break; 32 } 33 que2.push(word); 34 st.insert(word); 35 } 36 } 37 if (findAns) { 38 break; 39 } 40 } 41 ans++; 42 if (findAns) { 43 break; 44 } 45 swap(que, que2); 46 } 47 return findAns ? ans : 0; 48 } 49 };
2018年12月28日補充,直接bfs就好了,如今寫的很快。
1 class Solution { 2 public: 3 int ladderLength(string beginWord, string endWord, vector<string>& wordList) { 4 set<string> st(wordList.begin(), wordList.end()); 5 if (st.find(endWord) == st.end()) {return 0;} 6 const int n = wordList.size(); 7 int step = 0; 8 vector<int> visit(n, 0); 9 queue<string> que; 10 que.push(beginWord); 11 while (!que.empty()) { 12 const int size = que.size(); 13 step++; 14 for (int i = 0; i < size; ++i) { 15 string cur = que.front(); que.pop(); 16 for (int k = 0; k < n; ++k) { 17 if (visit[k]) {continue;} 18 if (diff(cur, wordList[k]) == 1) { 19 visit[k] = 1; 20 que.push(wordList[k]); 21 if (wordList[k] == endWord) { 22 return step + 1; 23 } 24 } 25 } 26 } 27 } 28 return 0; 29 } 30 int diff(string s1, string s2) { 31 if (s1.size() != s2.size()) {return -1;} 32 int cnt = 0; 33 for (int i = 0; i < s1.size(); ++i) { 34 if (s1[i] != s2[i]) { 35 ++cnt; 36 } 37 } 38 return cnt; 39 } 40 };
【130】Surrounded Regions
給了一個矩陣,有字母 ‘O’ 和 ‘X’ 組成,要求把由X包圍的全部O都反轉成X。 跟邊界上的O相連的O就不算被X包圍。
題解:直接dfs, floodfill。
1 class Solution { 2 public: 3 int dirx[4] = {-1, 0, 1, 0}; 4 int diry[4] = {0, -1, 0, 1}; 5 void solve(vector<vector<char>>& board) { 6 n = board.size(); 7 if (n == 0) {return;} 8 m = board[0].size(); 9 if (m == 0) {return;} 10 //mat 0: 沒有訪問過的,2:和邊界上的O相連的 11 vector<vector<int>> mat(n, vector<int>(m, 0)); 12 for (int i = 0; i < n; ++i) { 13 if (mat[i][0] == 0 && board[i][0] == 'O') { 14 floodfill(board, mat, i, 0); 15 } 16 if (mat[i][m-1] == 0 && board[i][m-1] == 'O') { 17 floodfill(board, mat, i, m -1); 18 } 19 } 20 for (int j = 0; j < m; ++j) { 21 if (mat[0][j] == 0 && board[0][j] == 'O') { 22 floodfill(board, mat, 0, j); 23 } 24 if (mat[n-1][j] == 0 && board[n-1][j] == 'O') { 25 floodfill(board, mat, n-1, j); 26 } 27 } 28 29 for (int i = 0; i < n; ++i) { 30 for (int j = 0; j < m; ++j) { 31 board[i][j] = mat[i][j] == 2 ? 'O' : 'X'; 32 } 33 } 34 return; 35 36 } 37 void floodfill(vector<vector<char>>& board, vector<vector<int>>& mat, int x, int y) { 38 mat[x][y] = 2; 39 for (int i = 0; i < 4; ++i) { 40 int newx = x + dirx[i], newy = y + diry[i]; 41 if (newx >= 0 && newx < n && newy >= 0 && newy < m && board[newx][newy] == 'O' && mat[newx][newy] == 0) { 42 floodfill(board, mat, newx, newy); 43 } 44 } 45 } 46 int n, m; 47 };
【133】Clone Graph
題目要求克隆一張圖,返回這張圖的深拷貝。
題解:這題糾結比較久,主要是由於指針不熟了,爲啥p2指針必定要在外面定義,要解決這個問題。這題須要review。
1 /** 2 * Definition for undirected graph. 3 * struct UndirectedGraphNode { 4 * int label; 5 * vector<UndirectedGraphNode *> neighbors; 6 * UndirectedGraphNode(int x) : label(x) {}; 7 * }; 8 */ 9 class Solution { 10 public: 11 UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) { 12 if (!node) {return node;} 13 queue<UndirectedGraphNode *> que; 14 que.push(node); 15 unordered_map<UndirectedGraphNode *, UndirectedGraphNode *> mp; 16 17 UndirectedGraphNode *ans = new UndirectedGraphNode(node->label); 18 mp[node] = ans; 19 UndirectedGraphNode* p2 = ans; 20 21 while (!que.empty()) { 22 UndirectedGraphNode *oriNode = que.front(); 23 p2 = mp[oriNode]; 24 que.pop(); 25 26 vector<UndirectedGraphNode *> nei = oriNode->neighbors; 27 for (int i = 0; i < nei.size(); ++i) { 28 if (mp.find(nei[i]) != mp.end()) { 29 p2->neighbors.push_back(mp[nei[i]]); 30 continue; 31 } 32 que.push(nei[i]); 33 UndirectedGraphNode * newNode = new UndirectedGraphNode(nei[i]->label); 34 mp[nei[i]] = newNode; 35 p2->neighbors.push_back(newNode); 36 } 37 38 } 39 return ans; 40 } 41 };
【199】Binary Tree Right Side View
一棵二叉樹,返回從右看能看到的數值,(只能看到每層最右的值),從上到下返回一個數組。
題解:仍是層級遍歷的變種。一次過了。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<int> rightSideView(TreeNode* root) { 13 vector<int> ans; 14 if (!root) { return ans; } 15 queue<TreeNode*> que, que2; 16 que.push(root); 17 while (!que.empty()) { 18 while (!que.empty()) { 19 TreeNode* node = que.front(); 20 que.pop(); 21 if (que.size() == 0) { 22 ans.push_back(node->val); 23 } 24 if (node->left) { que2.push(node->left); } 25 if (node->right) { que2.push(node->right); } 26 } 27 swap(que, que2); 28 } 29 return ans; 30 } 31 };
【200】Number of Islands
給了一個01矩陣,1的連通塊表明一個島,0表明水,問一共有幾個島。 (連通是四連通)
題解:直接dfs
1 class Solution { 2 public: 3 int numIslands(vector<vector<char>>& grid) { 4 n = grid.size(); 5 if (n == 0) {return 0;} 6 m = grid[0].size(); 7 if (m == 0) {return 0;} 8 vector<vector<int>> vis(n, vector<int>(m, 0)); 9 int ans = 0; 10 for (int i = 0; i < n; ++i) { 11 for (int j = 0; j < m; ++j) { 12 if (grid[i][j] == '1' && !vis[i][j]) { 13 dfs(grid, vis, i, j); 14 ans++; 15 } 16 } 17 } 18 return ans; 19 } 20 void dfs(const vector<vector<char>>& grid, vector<vector<int>>& vis, int x, int y) { 21 vis[x][y] = 1; 22 for (int i = 0; i < 4; ++i) { 23 int newx = x + dirx[i], newy = y + diry[i]; 24 if (newx >= 0 && newx < n && newy >= 0 && newy < m && !vis[newx][newy] && grid[newx][newy] == '1') { 25 dfs(grid, vis, newx, newy); 26 } 27 } 28 } 29 30 int n, m; 31 int dirx[4] = {-1, 0, 1, 0}; 32 int diry[4] = {0, -1, 0, 1}; 33 34 };
【207】Course Schedule (2019年1月20日,topologic sort 的bfs形式)
給了n門課程,有些課程在修以前有前置課程,給出了這些前置限制,判斷這些課程可否修完。
題解:直接拓撲排序。
1 class Solution { 2 public: 3 bool dfs(const vector<vector<int>>& g, vector<int>& c, int u) { 4 c[u] = -1; 5 for (int v = 0; v < n; ++v) { 6 if (g[u][v]) { 7 if (c[v] < 0) { return false; } 8 else if (!c[v] && !dfs(g, c, v)) { 9 return false; 10 } 11 } 12 } 13 c[u] = 1; 14 topo[--t] = u; 15 return true; 16 } 17 bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) { 18 vector<vector<int>> graph(numCourses, vector<int>(numCourses, 0)); 19 n = numCourses; 20 topo.resize(n); 21 t = n; 22 for (auto ele : prerequisites) { 23 int u = ele.first, v = ele.second; 24 graph[v][u] = 1; 25 } 26 vector<int> c(n, 0); 27 for (int i = 0; i < n; ++i) { 28 if (!c[i]) { 29 if (!dfs(graph, c, i)) { 30 return false; 31 } 32 } 33 } 34 /* 35 for (int i = 0; i < n; ++i) { 36 cout << topo[i] << " " ; 37 } 38 cout << endl; 39 */ 40 return true; 41 } 42 vector<int> topo; 43 int n, t; 44 };
2019年1月20日更新,topologic sort 的bfs形式更加好寫。也更好理解。
咱們先建圖(鄰接鏈表),而後去計算入度,而後把入度爲0的點全都放進隊列。開始bfs。注意此次bfs的循環結束條件是 for(int i = 0; i < n; ++i) 由於可能有環。
1 class Solution { 2 public: 3 bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) { 4 vector<vector<int>> g = initGraph(numCourses, prerequisites); 5 vector<int> degree = calDegree(g); 6 //find the vertex where degree == 0 and push them all into queue. 7 queue<int> que; 8 for (int i = 0; i < degree.size(); ++i) { 9 if (degree[i] == 0) { 10 que.push(i); 11 } 12 } 13 //start topologic sort 14 int idx = 0; 15 for (; idx < numCourses; ++idx) { 16 if (que.empty()) { 17 return false; 18 } 19 int cur = que.front(); que.pop(); 20 for (auto v : g[cur]) { 21 if (--degree[v] == 0) { 22 que.push(v); 23 } 24 } 25 } 26 return true; 27 } 28 private: 29 vector<vector<int>> initGraph(int n, vector<pair<int, int>>& pre) { 30 vector<vector<int>> g(n, vector<int>()); 31 for (auto e : pre) { 32 int start = e.second, end = e.first; 33 g[start].push_back(end); 34 } 35 return g; 36 } 37 vector<int> calDegree(vector<vector<int>>& g) { 38 vector<int> d(g.size(), 0); 39 const int n = g.size(); 40 for (auto e : g) { 41 for (auto v : e) { 42 d[v]++; 43 } 44 } 45 return d; 46 } 47 };
【210】Course Schedule II (2019年1月20日,topologic sort 的bfs形式)
跟207同樣,區別在於這題須要返回合法順序。
題解:拓撲排序。
1 class Solution { 2 public: 3 vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) { 4 vector<vector<int>> graph(numCourses, vector<int>(numCourses, 0)); 5 n = numCourses; 6 topo.resize(n); 7 t = n; 8 for (auto ele : prerequisites) { 9 int u = ele.first, v = ele.second; 10 graph[v][u] = 1; 11 } 12 vector<int> c(n, 0); 13 for (int i = 0; i < n; ++i) { 14 if (!c[i]) { 15 if (!dfs(graph, c, i)) { 16 topo.clear(); 17 return topo; 18 } 19 } 20 } 21 return topo; 22 } 23 bool dfs(const vector<vector<int>>& g, vector<int>& c, int u) { 24 c[u] = -1; 25 for (int v = 0; v < n; ++v) { 26 if (g[u][v]) { 27 if (c[v] < 0) { return false; } 28 else if (!c[v] && !dfs(g, c, v)) { 29 return false; 30 } 31 } 32 } 33 c[u] = 1; 34 topo[--t] = u; 35 return true; 36 } 37 vector<int> topo; 38 int n, t; 39 };
bfs 版本,特別簡單。
1 class Solution { 2 public: 3 vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) { 4 vector<vector<int>> g = initGraph(numCourses, prerequisites); 5 vector<int> degree = calDegree(g); 6 vector<int> ret(numCourses, 0); 7 queue<int> que; 8 for (int i = 0; i < degree.size(); ++i) { 9 if (degree[i] == 0) { 10 que.push(i); 11 } 12 } 13 for (int i = 0; i < numCourses; ++i) { 14 if (que.empty()) { 15 return vector<int>(); 16 } 17 int cur = que.front(); que.pop(); 18 ret[i] = cur; 19 for (auto e : g[cur]) { 20 if (--degree[e] == 0) { 21 que.push(e); 22 } 23 } 24 } 25 return ret; 26 } 27 private: 28 vector<vector<int>> initGraph(int n, vector<pair<int, int>>& pre) { 29 vector<vector<int>> g(n, vector<int>()); 30 for (auto e : pre) { 31 int start = e.second, end = e.first; 32 g[start].push_back(end); 33 } 34 return g; 35 } 36 vector<int> calDegree(vector<vector<int>>& g) { 37 vector<int> d(g.size(), 0); 38 const int n = g.size(); 39 for (auto e : g) { 40 for (auto v : e) { 41 d[v]++; 42 } 43 } 44 return d; 45 } 46 };
【261】Graph Valid Tree
今天一下子再看。
【279】Perfect Squares (2019年1月26日,谷歌tag複習)
給了一個正整數n, 求最少須要幾個徹底平方數(1, 4, 9, 16...)才能湊成和是n。
題解:看了小Q的題解,一個月以後寫仍是不會寫。==
首先咱們能夠分析出來,由於1是個徹底平方數,因此,n能夠爲任意正整數。只不過是最少怎麼求的問題。 咱們能夠設置一個數組f,f[i]表示i最少須要幾個徹底平方數表示。
轉移方程就是 f[m] = f[i + t*t] = f[i] +1。 咱們用一個隊列存儲已經求出來的 m = i + t * t。
1 class Solution { 2 public: 3 int numSquares(int n) { 4 vector<int> f(n+1, -1); 5 f[0] = 0; 6 queue<int> que; 7 que.push(0); 8 int m = 0; 9 while (!que.empty()) { 10 int m = que.front(); 11 que.pop(); 12 for (int i = 1; i * i + m <= n; ++i) { 13 if (f[i * i + m] == -1) { 14 f[i*i+m] = f[m] + 1; 15 que.push(i * i + m); 16 } 17 } 18 } 19 return f[n]; 20 } 21 };
【286】Walls and Gates
一個矩陣,0表明大門,1表明障礙物,INF表明能夠走的方塊。要求返回這個矩陣,把可達的INF都換成離門的最短距離。
題解:相似於bfs,從大門開始一層一層標記INF。
1 class Solution { 2 public: 3 void wallsAndGates(vector<vector<int>>& rooms) { 4 n = rooms.size(); 5 if (n == 0) { return; } 6 m = rooms[0].size(); 7 if (m == 0) { return; } 8 9 vector<pair<int, int>> begin; 10 for (int i = 0; i < n; ++i) { 11 for (int j = 0; j < m; ++j) { 12 if (rooms[i][j] == 0) { 13 begin.push_back(make_pair(i, j)); 14 } 15 } 16 } 17 for (auto b : begin) { 18 queue<pair<int, int>> que; 19 que.push(b); 20 for (; !que.empty(); que.pop()) { 21 pair<int, int> p = que.front(); 22 int x = p.first, y = p.second; 23 for (int i = 0; i < 4; ++i) { 24 int newx = x + dirx[i], newy = y + diry[i]; 25 if (newx >= 0 && newx < n && newy >= 0 && newy < m && rooms[newx][newy] != -1) { 26 if (rooms[newx][newy] > rooms[x][y] + 1) { 27 rooms[newx][newy] = rooms[x][y] + 1; 28 que.push(make_pair(newx, newy)); 29 } 30 } 31 } 32 } 33 } 34 return; 35 } 36 int n, m; 37 int dirx[4] = {-1, 0 ,1, 0}; 38 int diry[4] = {0, -1, 0, 1}; 39 };
【301】Remove Invalid Parentheses
【310】Minimum Height Trees (算法羣, 2018年11月13日)
給了一個有樹特徵的無向圖,咱們能夠選任何一個結點做爲樹的根,而後這個圖就能夠變成一個有根樹。在全部可能的有根樹中,高度最小的就叫作 MHT, 寫一個函數,要求返回這個圖的 MHT 的全部的根。
題解:我一開始是直接暴力枚舉每一個結點做爲樹的根結點,而後用bfs求樹的高度,比較最小值。時間複雜度是 O(N^2),超時了。 後來看了答案和羣裏,小Q的視頻, 和discuss。有 O(N) 的解法。咱們想象一下,咱們每次能夠去除一棵樹的最外層的葉子結點(葉子結點的 degree 是 1),一層一層從外往裏面剝洋蔥,最後內心的結點就是所求樹的根。
1 class Solution { 2 public: 3 vector<int> findMinHeightTrees(int n, vector<pair<int, int>>& edges) { 4 if (n == 0) {return vector<int>(); } 5 if (n == 1) {return vector<int>{0};} 6 vector<unordered_set<int>> edge(n, unordered_set<int>{}); 7 vector<int> degree(n, 0); 8 //init graph 9 for (auto p : edges) { 10 edge[p.first].insert(p.second); 11 edge[p.second].insert(p.first); 12 degree[p.first]++, degree[p.second]++; 13 } 14 //bfs 15 queue<int> que; 16 //put all leaves nodes into queue 17 for (int i = 0; i < n; ++i) { 18 if (degree[i] == 1) { 19 que.push(i); 20 } 21 } 22 //bfs 23 vector<int> ret(0); 24 while (!que.empty()) { 25 int size = que.size(); 26 ret.clear(); 27 for (int i = 0; i < size; ++i) { 28 int node = que.front(); que.pop(); 29 ret.push_back(node); 30 for (auto adj : edge[node]) { 31 degree[adj]--; 32 if (degree[adj] == 1) { //new leaves 33 que.push(adj); 34 } 35 } 36 } 37 } 38 return ret; 39 } 40 };
小Q的視頻地址以下:https://www.bilibili.com/video/av13605504/?p=4 他用了dfs,我沒怎麼看懂,估計仍是題量不夠。唉。
而後discuss的連接:https://leetcode.com/problems/minimum-height-trees/discuss/76055/Share-some-thoughts
【317】Shortest Distance from All Buildings
【323】Number of Connected Components in an Undirected Graph
【407】Trapping Rain Water II
【417】Pacific Atlantic Water Flow
【429】N-ary Tree Level Order Traversal
【490】The Maze
給了一個二維矩陣作迷宮(0表明能夠走, 1表明障礙物),一個小球,給了小球的開始位置和結束位置,問小球可否中止在結束位置。小球能夠四個方向滾動,可是它只會碰到牆/障礙物纔會中止,而後才能改變運動方向。
題解:能夠dfs,也能夠bfs。一開始以爲糾結的地方就是vis數組是小球通過這個位置就設置爲1,仍是隻有小球中止在當前位置才能設置爲1。後來看了別人的解法,只有小球在某個位置中止,才能把那個位置設置爲1。
1 class Solution { 2 public: 3 bool dfs(int cur_x, int cur_y) { 4 if (cur_x == des.first && cur_y == des.second) { 5 return true; 6 } 7 vis[cur_x][cur_y] = 1; 8 for (int i = 0; i < 4; ++i) { 9 int new_x = cur_x + dirx[i], new_y = cur_y + diry[i]; 10 while (new_x >= 0 && new_x < n && new_y >= 0 && new_y < m && mat[new_x][new_y] == 0) { 11 new_x += dirx[i], new_y += diry[i]; 12 } 13 new_x -= dirx[i], new_y -= diry[i]; 14 if (!vis[new_x][new_y]) { //vis數組只在停留的地方有用。 15 bool temp = dfs(new_x, new_y); 16 if (temp) { return true; } 17 } 18 } 19 return false; 20 } 21 bool hasPath(vector<vector<int>>& maze, vector<int>& start, vector<int>& destination) { 22 st.first = start[0], st.second = start[1], des.first = destination[0], des.second = destination[1]; 23 n = maze.size(), m = maze[0].size(); 24 vector<vector<int>> temp(n, vector<int>(m, 0)); 25 vis = temp; 26 mat = maze; 27 return dfs(st.first, st.second); 28 29 } 30 vector<vector<int>> vis, mat; 31 pair<int, int> st, des; 32 int n, m; 33 int dirx[4] = {-1, 0, 1, 0}; 34 int diry[4] = {0, -1, 0, 1}; 35 };
1 class Solution { 2 public: 3 bool hasPath(vector<vector<int>>& maze, vector<int>& start, vector<int>& destination) { 4 st.first = start[0], st.second = start[1], des.first = destination[0], des.second = destination[1]; 5 n = maze.size(), m = maze[0].size(); 6 vector<vector<int>> vis(n, vector<int>(m, 0)); 7 queue<pair<int, int>> que; 8 que.push(st); 9 for ( ;!que.empty(); que.pop()) { 10 pair<int, int> cur = que.front(); 11 for (int i = 0; i < 4; ++i) { 12 int new_x = cur.first + dirx[i], new_y = cur.second + diry[i]; 13 while (new_x >= 0 && new_x < n && new_y >= 0 && new_y < m && maze[new_x][new_y] == 0) { 14 new_x += dirx[i], new_y += diry[i]; 15 } 16 new_x -= dirx[i], new_y -= diry[i]; 17 if (new_x == des.first && new_y == des.second) { 18 return true; 19 } 20 if (!vis[new_x][new_y]) { 21 vis[new_x][new_y] = 1; 22 que.push(make_pair(new_x, new_y)); 23 } 24 } 25 } 26 return false; 27 } 28 pair<int, int> st, des; 29 int n, m; 30 int dirx[4] = {-1, 0, 1, 0}; 31 int diry[4] = {0, -1, 0, 1}; 32 };
【499】The Maze III
題目背景和490題差很少,就是小球走迷宮。可是一開始給了一個球的位置和一個洞的位置。(不一樣的是本題是洞,小球通過洞就能掉下去。而上一題是中止位置,小球必須撞到障礙物才能中止。)要求返回小球能不能落進洞裏,若是能,返回最短路徑的方向。若是有多條最短路,那麼返回方向字典序最小的那個。很差寫,須要review。
題解:仍是bfs。我一開始想的是用一個字符標記從這個點走的方向,可是不行。(判斷不出來是否是方向字典序最短)。後來看了discuss,是用了一個string標記從開始位置到當前位置的全部的方向,這樣若是有新的路徑比原來的路徑短,就更新string和路徑長度,若是有一條新的路徑和原來的路徑同樣長,就判斷誰的字典序小就用誰。
1 class Solution { 2 public: 3 string findShortestWay(vector<vector<int>>& maze, vector<int>& ball, vector<int>& hole) { 4 st.first = ball[0], st.second = ball[1], des.first = hole[0], des.second = hole[1]; 5 n = maze.size(), m = maze[0].size(); 6 vector<vector<point>> cnt(n, vector<point>(m, point())); //cnt[x][y] --> (path, tot) 7 queue<pair<int, int>> que; 8 cnt[st.first][st.second].tot = 0; 9 que.push(st); 10 bool findAns = false; 11 for ( ;!que.empty(); que.pop()) { 12 pair<int, int> cur = que.front(); 13 int curx = cur.first, cury = cur.second; 14 for (int i = 0; i < 4; ++i) { 15 int newx = curx + dirx[i], newy = cury + diry[i], step = 1; 16 bool onRoad = false; 17 while (newx >= 0 && newx < n && newy >= 0 && newy < m && maze[newx][newy] == 0) { 18 //若是hole就在當前的路上,球能掉進洞裏 19 if (newx == des.first && newy == des.second) { 20 findAns = true; onRoad = true; 21 if (cnt[newx][newy].tot == -1 || cnt[newx][newy].tot > step + cnt[curx][cury].tot) { 22 cnt[newx][newy].tot = step + cnt[curx][cury].tot; 23 cnt[newx][newy].path = cnt[curx][cury].path + dir2str[i]; 24 } else if (cnt[newx][newy].tot == step + cnt[curx][cury].tot) {//若是最短路徑相等,可是新的路徑字典序更小,更新路徑 25 string newPath = cnt[curx][cury].path + dir2str[i]; 26 if (cnt[newx][newy].path > newPath) { 27 cnt[newx][newy].path = newPath; 28 } 29 } 30 break; 31 } 32 newx += dirx[i], newy += diry[i], step++; 33 } 34 //若是洞不在路上,就更新撞到牆的那個點 35 if (!onRoad) { 36 newx -= dirx[i], newy -= diry[i], step--; 37 if (cnt[newx][newy].tot == -1 || cnt[newx][newy].tot > step + cnt[curx][cury].tot) { 38 cnt[newx][newy].tot = step + cnt[curx][cury].tot; 39 cnt[newx][newy].path = cnt[curx][cury].path + dir2str[i]; 40 que.push(make_pair(newx, newy)); 41 } else if (cnt[newx][newy].tot == step + cnt[curx][cury].tot) { //若是最短路徑相等,可是新的路徑字典序更小,更新路徑,而後把這個點從新放進隊列裏面。 42 string newPath = cnt[curx][cury].path + dir2str[i]; 43 if (cnt[newx][newy].path > newPath) { 44 cnt[newx][newy].path = newPath; 45 que.push(make_pair(newx, newy)); 46 } 47 } 48 } 49 } 50 } 51 string ans; 52 if (!findAns) { 53 ans = "impossible"; 54 return ans; 55 } 56 ans = cnt[des.first][des.second].path; 57 return ans; 58 } 59 pair<int, int> st, des; 60 int n, m; 61 int dirx[4] = {0, -1, 1, 0}; 62 int diry[4] = {1, 0, 0, -1}; 63 string dir2str[4] = {"r", "u", "d", "l"}; 64 struct point { 65 point():path(""), tot(-1) { 66 67 } 68 string path; //到每一個點並且知足條件的最短路徑 69 int tot; //到每一個點的最短路徑長度 70 }; 71 };
【505】The Maze II
題目背景和490題同樣,都是小球在迷宮裏面走。這題不一樣之處要求出小球從開始位置走到結束位置的最短距離,不可達返回-1。
題解:直接bfs了。有一點須要注意,若是有一個點到開始位置的距離更新了,那麼這個點要從新放回隊列裏面搜索。否則最小距離更新的不許。
1 class Solution { 2 public: 3 int shortestDistance(vector<vector<int>>& maze, vector<int>& start, vector<int>& destination) { 4 st.first = start[0], st.second = start[1], des.first = destination[0], des.second = destination[1]; 5 n = maze.size(), m = maze[0].size(); 6 vector<vector<int>> cnt(n, vector<int>(m, -1)); 7 queue<pair<int, int>> que; 8 cnt[st.first][st.second] = 0; 9 que.push(st); 10 bool findAns = false; 11 int ans = 0; 12 for (; !que.empty(); que.pop()) { 13 pair<int, int> cur = que.front(); 14 for (int i = 0; i < 4; ++i) { 15 int newx = cur.first + dirx[i], newy = cur.second + diry[i], step = 1; 16 while (newx >= 0 && newx < n && newy >= 0 && newy < m && maze[newx][newy] == 0) { 17 newx += dirx[i], newy += diry[i], step++; 18 } 19 newx -= dirx[i], newy -= diry[i], step--; 20 if (cnt[newx][newy] == -1) { 21 cnt[newx][newy] = step + cnt[cur.first][cur.second]; 22 que.push(make_pair(newx, newy)); 23 } else if (cnt[newx][newy] > step + cnt[cur.first][cur.second]){ 24 que.push(make_pair(newx, newy)); //若是當前點的最短距離有更新的話, 依然要push進入隊列,否則最小距離不許的。 25 cnt[newx][newy] = min(cnt[newx][newy], step + cnt[cur.first][cur.second]) ; 26 } 27 if (newx == des.first && newy == des.second) { 28 findAns = true; 29 } 30 } 31 } 32 return findAns ? cnt[des.first][des.second] : -1; 33 } 34 pair<int, int> st, des; 35 int n, m; 36 int dirx[4] = {-1, 0, 1, 0}; 37 int diry[4] = {0, -1, 0, 1}; 38 };
【513】Find Bottom Left Tree Value
給了一棵二叉樹,返回這棵樹最後一層的最左邊的節點的值。
題解:二叉樹的層級遍歷,直接bfs。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 int findBottomLeftValue(TreeNode* root) { 13 if (!root) {return -1;} 14 queue<TreeNode*> que, que2; 15 vector<int> level; 16 que.push(root); 17 int ans = -1; 18 while (!que.empty()) { 19 while (!que.empty()) { 20 TreeNode* node = que.front(); que.pop(); 21 level.push_back(node->val); 22 if (node->left) { que2.push(node->left); } 23 if (node->right) { que2.push(node->right); } 24 } 25 swap(que, que2); 26 ans = level[0]; 27 level.clear(); 28 } 29 return ans; 30 } 31 };
【515】Find Largest Value in Each Tree Row
給了一棵二叉樹,返回每層的最大值。
題解:二叉樹的層級遍歷,直接bfs。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 vector<int> largestValues(TreeNode* root) { 13 vector<int> ans; 14 queue<TreeNode*> que, que2; 15 if (!root) {return ans;} 16 que.push(root); 17 while (!que.empty()) { 18 int maxx = INT_MIN; 19 while (!que.empty()) { 20 TreeNode* node = que.front(); 21 que.pop(); 22 maxx = max(node->val, maxx); 23 if (node->left) {que2.push(node->left);} 24 if (node->right) {que2.push(node->right);} 25 } 26 ans.push_back(maxx); 27 swap(que, que2); 28 } 29 return ans; 30 } 31 };
【529】Minesweeper
【542】01 Matrix (2019年2月23日)
Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.
The distance between two adjacent cells is 1.
Example 2: Input: 0 0 0 0 1 0 1 1 1 Output: 0 0 0 0 1 0 1 2 1
題解:BFS
1 class Solution { 2 public: 3 vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) { 4 if (matrix.empty() || matrix[0].empty()) {return matrix;} 5 const int n = matrix.size(), m = matrix[0].size(); 6 vector<vector<int>> res = matrix; 7 queue<vector<int>> que; 8 for (int i = 0; i < n; ++i) { 9 for (int j = 0; j < m; ++j) { 10 if (matrix[i][j] == 0) { 11 que.push({i, j}); 12 } else { 13 res[i][j] = -1; 14 } 15 } 16 } 17 const vector<int> dirx = {-1, 0 ,1, 0}; 18 const vector<int> diry = {0 ,-1, 0, 1}; 19 int step = 1; 20 while (!que.empty()) { 21 int size = que.size(); 22 for (int i = 0; i < size; ++i, que.pop()) { 23 auto x = que.front()[0], y = que.front()[1]; 24 for (int k = 0; k < 4; ++k) { 25 int newx = x + dirx[k], newy = y + diry[k]; 26 if (newx < 0 || newx >= n || newy < 0 || newy >= m) {continue;} 27 if (res[newx][newy] != -1) {continue;} 28 res[newx][newy] = step; 29 que.push({newx, newy}); 30 } 31 } 32 ++step; 33 } 34 return res; 35 } 36 };
【559】Maximum Depth of N-ary Tree
【675】Cut Off Trees for Golf Event
【690】Employee Importance
給了一個數據結構,[1, 15, [2]], 表明1號員工他的value是15,他的下屬是2號員工。輸入一個這樣的數據結構的數組,和一個員工編號。返回這個員工和他全部的直接下屬和間接下屬的價值之和。
題解:直接bfs。
1 /* 2 // Employee info 3 class Employee { 4 public: 5 // It's the unique ID of each node. 6 // unique id of this employee 7 int id; 8 // the importance value of this employee 9 int importance; 10 // the id of direct subordinates 11 vector<int> subordinates; 12 }; 13 */ 14 class Solution { 15 public: 16 int getImportance(vector<Employee*> employees, int id) { 17 int ans = 0; 18 queue<int> que; 19 que.push(id); 20 for (; !que.empty(); que.pop()) { 21 int user = que.front(); 22 Employee* ptr = 0; 23 for (int i = 0; i < employees.size(); ++i) { 24 ptr = employees[i]; 25 if (ptr->id == user) { 26 break; 27 } 28 } 29 if (ptr == 0) { 30 cout << "err" << endl; 31 return -1; 32 } 33 ans += ptr->importance; 34 for (int i = 0; i < ptr->subordinates.size(); ++i) { 35 que.push(ptr->subordinates[i]); 36 } 37 } 38 return ans; 39 } 40 };
【743】Network Delay Time
【752】Open the Lock (2018年11月29日,算法羣)
一個字符串四個字符,開始位置是 「0000」, 給了一個集合,裏面限制了這個字符串不能轉換到這個集合裏面的元素,不然算這個遊戲掛了。給了一個終點字符串 target,問從 「0000」 開始至少要通過多少步能到達 target。一步的定義是一個字符加一或者減一(0-9循環),好比,'1' -> '0' ,'0'->'1', '0'->'9', '9->0'。
題解:bfs,難點是生成下一個結點的集合。(直接暴力生成) 這題solution也是這個解法,可是300+ms,beats 10%不到。爲啥呢,真的很慢了。
1 //本題的重點是如何生成不在 deadends 裏面的下一個結點。 2 class Solution { 3 public: 4 int openLock(vector<string>& deadends, string target) { 5 set<string> st(deadends.begin(), deadends.end()); 6 set<string> visited; 7 if (st.find("0000") != st.end() || st.find(target) != st.end()) {return -1;} 8 queue<string> que; 9 que.push("0000"); visited.insert("0000"); 10 int step = 0; 11 bool findAns = false; 12 while (!que.empty()) { 13 const int size = que.size(); 14 for (int i = 0; i < size; ++i) { 15 string cur = que.front(); que.pop(); 16 if (cur == target) { findAns = true; break; } 17 vector<string> nextNodes = genNextNodes(cur, st, target); 18 for (auto node : nextNodes) { 19 if (visited.find(node) != visited.end()) {continue;} 20 que.push(node); 21 visited.insert(node); 22 } 23 } 24 if (findAns) { return step; } 25 step++; 26 } 27 return -1; 28 } 29 vector<string> genNextNodes(const string& cur, const set<string>& st, const string& target) { 30 vector<string> ret; 31 string temp = cur; 32 for (int i = 0; i < 4; ++i) { 33 int num = temp[i] - '0' + 10; 34 for (int dis = -1; dis <= 1; dis +=2) { 35 int newNum = (num + dis) % 10; 36 string str = temp.substr(0, i) + to_string(newNum) + temp.substr(i+1); 37 if (st.find(str) != st.end()) {continue;} 38 ret.push_back(str); 39 } 40 } 41 return ret; 42 } 43 };
【773】Sliding Puzzle (2019年3月10日, H)
八數碼問題
題解:bfs 用 encode棋盤成字符串的方式來保存狀態。
1 class Solution { 2 public: 3 int slidingPuzzle(vector<vector<int>>& board) { 4 queue<string> que; 5 string state = toString(board), target = "123450"; 6 if (state == target) {return 0;} 7 que.push(state); 8 unordered_set<string> st; 9 st.insert(state); 10 const int n = board.size(), m = board[0].size(); 11 int step = 0; 12 while (!que.empty()) { 13 int size = que.size(); 14 while (size--) { 15 string cur = que.front(); que.pop(); 16 toBoard(cur, board); 17 int pos = cur.find('0'); 18 int x = pos / m, y = pos % m; 19 for (int k = 0; k < 4; ++k) { 20 int newx = x + dirx[k], newy = y + diry[k]; 21 if (newx < 0 || newx >= n || newy < 0 || newy >= m) {continue;} 22 vector<vector<int>> newBoard(board); 23 swap(newBoard[x][y], newBoard[newx][newy]); 24 string newState = toString(newBoard); 25 if (newState == target) {return step + 1;} 26 if (st.find(newState) != st.end()) {continue;} 27 st.insert(newState); 28 que.push(newState); 29 } 30 } 31 step++; 32 } 33 return -1; 34 } 35 const int dirx[4] = {-1, 0, 1, 0}; 36 const int diry[4] = {0, -1, 0, 1}; 37 string toString(vector<vector<int>>& board) { 38 string res; 39 for (int i = 0; i < board.size(); ++i) { 40 for (int j = 0; j < board[i].size(); ++j) { 41 res += board[i][j] + '0'; 42 } 43 } 44 return res; 45 } 46 void toBoard(string& s, vector<vector<int>>& board) { 47 int m = board[0].size(); 48 for (int i = 0; i < s.size(); ++i) { 49 board[i/m][i%m] = s[i] - '0'; 50 } 51 } 52 };
【785】Is Graph Bipartite?
【787】Cheapest Flights Within K Stops
【815】Bus Routes
【847】Shortest Path Visiting All Nodes (算法羣 2018年10月24日) 這題似懂非懂,最後寫了一個BFS+狀態壓縮的寫法。可是彷佛能夠dp+狀態壓縮。
【854】K-Similar Strings
【863】All Nodes Distance K in Binary Tree
【864】Shortest Path to Get All Keys