// Potential improvements: // 1. we can use vector<int> { h, x, y } to replace Element, sorting vector is to compare elements one by one. // 2. use 2-d bool vector<vector<bool>> to replace unordered_set. class Element { public: int x, y, h; Element(int x, int y, int h) { this->x = x; this->y = y; this->h = h; } }; class Solution { public: int m; int n; int cutOffTree(vector<vector<int>>& forest) { m = forest.size(); if (m == 0) return 0; n = forest[0].size(); if (n == 0) return 0; vector<Element> v; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (forest[i][j] > 1) v.emplace_back(i, j, forest[i][j]); auto comp = [](const Element& a, const Element& b) { return a.h < b.h; }; v.emplace_back(0, 0, 0); sort(v.begin(), v.end(), comp); int res = 0; for (int i = 0; i < v.size() - 1; i++) { int t = helper(forest, v[i], v[i+1]); if (t < 0) return t; res += t; } return res; } int helper(vector<vector<int>>& forest, const Element& a, const Element& b) { const int dirs[] = { -1, 0, 1, 0, -1 }; // (x,y) is small enough, so x*n+y won't overflow. otherwise we have to use long, // and be careful x*n+y will overflow, we may use (long)x*n+y instead. unordered_set<int> s; queue<pair<int,int>> q; q.push({a.x, a.y}); s.insert(a.x * n + a.y); int lv = 0; while (!q.empty()) { int qsz = q.size(); for (int i = 0; i < qsz; i++) { auto cur = q.front(); q.pop(); if (cur.first == b.x && cur.second == b.y) return lv; for (int i = 0; i < 4; i++) { int nx = cur.first + dirs[i]; int ny = cur.second + dirs[i+1]; pair<int,int> np = {nx,ny}; if (nx >= 0 && nx < m && ny >= 0 && ny < n && forest[nx][ny] > 0 && s.find(nx * n + ny) == s.end()) { q.push(np); s.insert(nx * n + ny); } } } lv++; } return -1; } };
huge perf improve from 1000+ ms to 300 ms:
use 2-d bool vector<vector<bool>> to replace unordered_set
class Element { public: int x, y, h; Element(int x, int y, int h) { this->x = x; this->y = y; this->h = h; } }; class Solution { public: int m; int n; int cutOffTree(vector<vector<int>>& forest) { m = forest.size(); if (m == 0) return 0; n = forest[0].size(); if (n == 0) return 0; vector<Element> v; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (forest[i][j] > 1) v.emplace_back(i, j, forest[i][j]); auto comp = [](const Element& a, const Element& b) { return a.h < b.h; }; v.emplace_back(0, 0, 0); sort(v.begin(), v.end(), comp); int res = 0; for (int i = 0; i < v.size() - 1; i++) { int t = helper(forest, v[i], v[i+1]); if (t < 0) return t; res += t; } return res; } int helper(vector<vector<int>>& forest, const Element& a, const Element& b) { const int dirs[] = { -1, 0, 1, 0, -1 }; // (x,y) is small enough, so x*n+y won't overflow. otherwise we have to use long, // and be careful x*n+y will overflow, we may use (long)x*n+y instead. vector<vector<bool>> s(m, vector<bool>(n)); queue<pair<int,int>> q; q.emplace(a.x, a.y); s[a.x][a.y] = true; int lv = 0; while (!q.empty()) { int qsz = q.size(); for (int i = 0; i < qsz; i++) { auto cur = q.front(); q.pop(); if (cur.first == b.x && cur.second == b.y) return lv; for (int i = 0; i < 4; i++) { int nx = cur.first + dirs[i]; int ny = cur.second + dirs[i+1]; pair<int,int> np = {nx,ny}; if (nx >= 0 && nx < m && ny >= 0 && ny < n && forest[nx][ny] > 0 && !s[nx][ny]) { q.push(np); s[nx][ny] = true; } } } lv++; } return -1; } };