# Matrix ###### tags: `Study_aboard` ## Spiral Matrix ![](https://i.imgur.com/80yPFHR.png) ```cpp class Solution { public: vector<int> spiralOrder(vector<vector<int>>& matrix) { int border_up=-1, border_down=matrix.size(), border_left=-1, border_right=matrix[0].size(); vector <int> res; char direction = 'r'; int cur_x=0, cur_y=0; while(res.size()<(matrix.size()*matrix[0].size()) ){ res.push_back(matrix[cur_x][cur_y]); if(direction == 'r'){ if(cur_y+1 < border_right){ cur_y = cur_y+1; } else{ direction = 'd'; border_up++; cur_x = cur_x+1; } } else if(direction == 'd'){ if(cur_x+1 < border_down){ cur_x = cur_x+1; } else{ direction = 'l'; border_right--; cur_y = cur_y-1; } } else if(direction == 'l'){ if(cur_y-1 > border_left){ cur_y = cur_y-1; } else{ direction = 'u'; border_down--; cur_x --; } } else if(direction == 'u'){ if(cur_x-1 > border_up){ cur_x = cur_x-1; } else{ direction = 'r'; border_left++; cur_y = cur_y+1; } } } return res; } }; ``` ## Search a 2d Matrix ![](https://i.imgur.com/cDC0Wwq.png) easy sorted array -> use binary search see https://hackmd.io/@chentzj/SkNIsGDpu binary search ```cpp class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { if (matrix.empty() || matrix[0].empty()) return false; int left = 0, right = matrix.size(); // row use binary search II - search the first number that is greater or equal to the target while (left < right) { int mid = (left + right) / 2; if (matrix[mid][0] == target) return true; if (matrix[mid][0] < target) left = mid + 1; else right = mid; } // right-1 will be the row we want int tmp = (right > 0) ? (right - 1) : right; left = 0; right = matrix[tmp].size(); // binary search I while (left < right) { int mid = (left + right) / 2; if (matrix[tmp][mid] == target) return true; if (matrix[tmp][mid] < target) left = mid + 1; else right = mid; } return false; } }; ``` ## Search a 2d Matrix II ![](https://i.imgur.com/aqybMG7.png) 要能夠search,需要先找出一致性。 觀察左下角與右上角,發現其邊有一致性,以左下角為例,其上方都是小於它的數字,而右方都是大於它的數字 ```cpp class Solution { public: bool searchMatrix(vector<vector<int> > &matrix, int target) { if (matrix.empty() || matrix[0].empty()) return false; if (target < matrix[0][0] || target > matrix.back().back()) return false; int x = matrix.size() - 1, y = 0; // x is row, y is col while (true) { if (matrix[x][y] > target) --x; else if (matrix[x][y] < target) ++y; else return true; if (x < 0 || y >= matrix[0].size()) break; } return false; } }; ``` ## Maximum Number of Points with Cost ![](https://i.imgur.com/2CesTNo.png) ![](https://i.imgur.com/daRhZlh.png) ![](https://i.imgur.com/79q3SMU.png) Initial : divide and conquer problem: TLE time complexity O(m * n * n) solution: find same computation to reduce complexity original version ```cpp class Solution { public: long long maxPoints(vector<vector<int>>& points) { long long int m = points.size(), n=points[0].size(); vector<vector<long long int>> dp(m, vector<long long int>(n, 0)); for(int i=0;i<n;i++){ dp[0][i] = points[0][i]; } // i is row, j is col for(int i=1;i<m;i++){ for(int j=0;j<n;j++){ long long int Max = INT_MIN; for(int k=0;k<n;k++){ Max = max(Max,points[i][j]+dp[i-1][k]-abs(j-k)); } dp[i][j] = Max; } } long long int res=0; for(int i=0;i<n;i++){ res = max(dp[m-1][i], res); } return res; } }; ``` Initial: ![](https://i.imgur.com/PnUV7Rn.png) Sol:若將abs(j-k)區分為 j-k (j>k) & k-j (k>j),==則j與k之間並沒有關係==,可以==獨立拆出==而不須在j loop中執行k。 ![](https://i.imgur.com/JkOhHup.png) ![](https://i.imgur.com/8k93qYM.png) ```cpp class Solution { public: long long maxPoints(vector<vector<int>>& points) { vector<vector<long long>> dp(points.size(), vector<long long>(points[0].size(), -1)); for (int i = 0; i < points[0].size(); ++i) { dp[0][i] = points[0][i]; } for (int i = 1; i < points.size(); ++i) { vector<long long> left_dp(points[i].size(), -1); vector<long long> right_dp(points[i].size(), -1); // left_dp : the maximum value of dp[i-1][k'] from 0~k // right_dp : the maximum value of dp[i-1][k'] from k~size()-1 left_dp[0] = dp[i - 1][0]; for (int k = 1; k < points[i].size(); ++k) { left_dp[k] = max(left_dp[k - 1], dp[i - 1][k] + k); } right_dp.back() = dp[i - 1].back() - points[i].size() + 1; for (int k = points[i].size() - 2; k >= 0; --k) { right_dp[k] = max(right_dp[k + 1], dp[i - 1][k] - k); } for (int j = 0; j < points[i].size(); ++j) { dp[i][j] = max(left_dp[j] - j, right_dp[j] + j) + points[i][j]; } } long long max_ans = -1; for (const auto v : dp.back()) { max_ans = max(max_ans, v); } return max_ans; } }; ``` ## Longest Increasing Path in a Matrix ![](https://i.imgur.com/RjSyf1C.png) 1. DFS ```cpp class Solution { public: int longestIncreasingPath(vector<vector<int>>& matrix) { vector<vector<int>> dp(matrix.size(), vector<int>(matrix[0].size(), 0)); int res = 0; for(int i=0;i<matrix.size();i++){ for(int j=0;j<matrix[0].size();j++){ res = max(res,dfs(i,j,dp, matrix)) ; } } return res; } int dfs(int i, int j, vector<vector<int>>& dp,vector<vector<int>>& matrix){ int mx = 1; int len = 0; int m = matrix.size(), n = matrix[0].size(); vector<vector<int>> dirs = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}}; for (auto a : dirs) { int x = i + a[0], y = j + a[1]; if (x < 0 || x >= m || y < 0 || y >= n || matrix[x][y] <= matrix[i][j]) continue; if (dp[x][y]){ len = 1 + dp[x][y]; } else{ len = 1 + dfs(x, y,dp, matrix); } mx = max(mx, len); } dp[i][j] = mx; return mx; } }; ``` ## Sparse Matrix ==Facebook, google== ![](https://i.imgur.com/xDxOiID.png) ![](https://i.imgur.com/vyMIcVN.png) Nothing sepcial ```cpp class Solution { public: /** * @param A: a sparse matrix * @param B: a sparse matrix * @return: the result of A * B */ vector<vector<int>> multiply(vector<vector<int>> &A, vector<vector<int>> &B) { vector< vector<int> > AB; AB.clear(); int rowA = A.size(), columnA = A[0].size(); int rowB = B.size(), columnB = B[0].size(); // AB为 rowA * columnB 大小的矩阵 for (int i = 0; i < rowA; i++){ vector<int> tmp; tmp.clear(); for (int j = 0; j < columnB; j++){ // 求出每一项 int sum = 0; for (int k = 0; k < columnA; k++){ sum += A[i][k] * B[k][j]; } tmp.push_back(sum); } AB.push_back(tmp); } return AB; } }; ``` ## Best meeting point ==Hard== good problem ![](https://i.imgur.com/LhcamM4.png) ![](https://i.imgur.com/Q5o2EuN.png) ==Hint simplify the question first!!!== ![](https://i.imgur.com/pPe3Ysq.png) ![](https://i.imgur.com/bJdwTEb.png) ```cpp class Solution { public: int minTotalDistance(vector<vector<int>>& grid) { vector<int> rows, cols; for (int i = 0; i < grid.size(); ++i) { for (int j = 0; j < grid[i].size(); ++j) { if (grid[i][j] == 1) { rows.push_back(i); cols.push_back(j); } } } return minTotalDistance(rows) + minTotalDistance(cols); } int minTotalDistance(vector<int> v) { int res = 0; sort(v.begin(), v.end()); int i = 0, j = v.size() - 1; while (i < j) res += v[j--] - v[i++]; return res; } }; ``` ## Minimum Garden Perimeter to Collect Enough Apples ![](https://i.imgur.com/9YGqQKI.png) ![](https://i.imgur.com/eH2jg5M.png) ![](https://i.imgur.com/Eg4ROKf.png) Perimeter i = Perimeter i-1 + additional items Additional items: - 最外面上下左右四點 + 在x軸與y軸上的四點 = $2n*4 + n*4$ = $12*n$ - 4 \* (在x軸到右上方的點n + 右上方到y軸上n) = $2n*(n-1)*4$ - 4 \* (在x軸到右上方的點1~n + 右上方到y軸上1~n) = $n*(n-1)*4$ Sum = $12*n^2$ ```cpp class Solution { public: long long minimumPerimeter(long long neededApples) { long long old_val=0, new_val=0; for(int i=1; ;i++){ new_val = old_val + 12 * pow(i,2); if(new_val>=neededApples) return i*2*4; else old_val = new_val; } return new_val; } }; ``` ## Walls and Gates ![](https://i.imgur.com/5PyU9fh.png) ![](https://i.imgur.com/P6asZG2.png) Initial: do BFS for each empty room until reach the gate If we reach a room that we are already done, we can return cur path + room path Sol: start from empty gates may be faster !! ```cpp class Solution { public: void wallsAndGates(vector<vector<int>>& rooms) { queue<pair<int, int>> q;// bfs queue for row and col vector<vector<int>> dirs{{0, -1}, {-1, 0}, {0, 1}, {1, 0}}; // bfs children for (int i = 0; i < rooms.size(); ++i) { for (int j = 0; j < rooms[i].size(); ++j) { if (rooms[i][j] == 0) q.push({i, j}); } } while (!q.empty()) { int i = q.front().first, j = q.front().second; q.pop(); for (int k = 0; k < dirs.size(); ++k) { int x = i + dirs[k][0], y = j + dirs[k][1]; /* child does not exist // rooms[x][y] < rooms[i][j] + 1 // 1. rooms[x][y] = -1 // 2. rooms[x][y] already walk through by a smaller distance gate */ if (x < 0 || x >= rooms.size() || y < 0 || y >= rooms[0].size() || rooms[x][y] < rooms[i][j] + 1) continue; rooms[x][y] = rooms[i][j] + 1; q.push({x, y}); } } } }; ``` ## Shortest Distance from all buildings ![](https://i.imgur.com/aX2CWTB.png) 初始想法:BFS算出每個building的distane map,加總取最小值 dist: temporary distane map sum: sum of each temporary distance map bfs: implement by queue visit: bfs需要記得已走過的位置,因此將做完後的grid--來達成。而下一輪==的val也要--。此處有可能有疑問,可能有上一個building無法走到的empty space而導致仍為0,但下一個building是能夠通過的。但由於題目規定need to reach all buildings,因此此empty space也不能作為路徑。 ```cpp class Solution { public: int shortestDistance(vector<vector<int>>& grid) { int res = INT_MAX, val = 0, m = grid.size(), n = grid[0].size(); vector<vector<int>> sum = grid; vector<vector<int>> dirs{{0,-1},{-1,0},{0,1},{1,0}}; for (int i = 0; i < grid.size(); ++i) { for (int j = 0; j < grid[i].size(); ++j) { if (grid[i][j] == 1) { res = INT_MAX; vector<vector<int>> dist = grid; queue<pair<int, int>> q; q.push({i, j}); while (!q.empty()) { int a = q.front().first, b = q.front().second; q.pop(); for (int k = 0; k < dirs.size(); ++k) { int x = a + dirs[k][0], y = b + dirs[k][1]; if (x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == val) { --grid[x][y]; dist[x][y] = dist[a][b] + 1; sum[x][y] += dist[x][y] - 1; q.push({x, y}); res = min(res, sum[x][y]); } } } --val; } } } return res == INT_MAX ? -1 : res; } }; ```