Given a matrix of M x N elements (M rows, N columns), return all elements of the matrix in diagonal order as shown in the below image.html
Example:java
Input: [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ] Output: [1,2,4,7,5,3,6,8,9] Explanation:
Note:數組
這道題給了咱們一個mxn大小的數組,讓咱們進行對角線遍歷,先向右上,而後左下,再右上,以此類推直至遍歷完整個數組,題目中的例子和圖示也能很好的幫咱們理解。因爲移動的方向再也不是水平或豎直方向,而是對角線方向,那麼每移動一次,橫縱座標都要變化,向右上移動的話要座標加上[-1, 1],向左下移動的話要座標加上[1, -1],那麼難點在於咱們如何處理越界狀況,越界後遍歷的方向怎麼變換。向右上和左下兩個對角線方向遍歷的時候都會有越界的可能,可是除了左下角和右上角的位置越界須要改變兩個座標以外,其他的越界只須要改變一個。那麼咱們就先判斷要同時改變兩個座標的越界狀況,即在右上角和左下角的位置。若是在右上角位置還要往右上走時,那麼要移動到它下面的位置的,那麼若是col超過了n-1的範圍,那麼col重置爲n-1,而且row自增2,而後改變遍歷的方向。同理若是row超過了m-1的範圍,那麼row重置爲m-1,而且col自增2,而後改變遍歷的方向。而後咱們再來判斷通常的越界狀況,若是row小於0,那麼row重置0,而後改變遍歷的方向。同理若是col小於0,那麼col重置0,而後改變遍歷的方向。參見代碼以下:post
解法一:url
class Solution { public: vector<int> findDiagonalOrder(vector<vector<int>>& matrix) { if (matrix.empty() || matrix[0].empty()) return {}; int m = matrix.size(), n = matrix[0].size(), r = 0, c = 0, k = 0; vector<int> res(m * n); vector<vector<int>> dirs{{-1,1}, {1,-1}}; for (int i = 0; i < m * n; ++i) { res[i] = matrix[r][c]; r += dirs[k][0]; c += dirs[k][1]; if (r >= m) {r = m - 1; c += 2; k = 1 - k;} if (c >= n) {c = n - 1; r += 2; k = 1 - k;} if (r < 0) {r = 0; k = 1 - k;} if (c < 0) {c = 0; k = 1 - k;} } return res; } };
下面這種方法跟上面的方法思路相同,不過寫法有些不一樣,這裏根據橫縱左邊之和的奇偶性來判斷遍歷的方向,而後對於越界狀況再單獨處理便可,參見代碼以下:spa
解法二:code
class Solution { public: vector<int> findDiagonalOrder(vector<vector<int>>& matrix) { if (matrix.empty() || matrix[0].empty()) return {}; int m = matrix.size(), n = matrix[0].size(), r = 0, c = 0; vector<int> res(m * n); for (int i = 0; i < m * n; ++i) { res[i] = matrix[r][c]; if ((r + c) % 2 == 0) { if (c == n - 1) {++r;} else if (r == 0) {++c;} else {--r; ++c;} } else { if (r == m - 1) {++c;} else if (c == 0) {++r;} else {++r; --c;} } } return res; } };
下面這種方法是按遍歷方向來按規律往結果res中添加數字的,好比題目中的那個例子,那麼添加的順序以下:htm
[0,0] -> [0,1],[1,0] -> [2,0],[1,1],[0,2] -> [1,2],[2,1] -> [2,2]blog
根據遍歷的方向不一樣共分爲五層,關鍵就是肯定每一層的座標範圍,其中下邊界low = max(0, i - n + 1),這樣能夠保證下邊界不會小於0,而上邊界high = min(i, m - 1),這樣也保證了上邊界不會大於m-1,若是是偶數層,則從上邊界往下邊界遍歷,反之若是是奇數層,則從下邊界往上邊界遍歷,注意從matrix中取數字的座標,,參見代碼以下:ci
解法三:
class Solution { public: vector<int> findDiagonalOrder(vector<vector<int>>& matrix) { if (matrix.empty() || matrix[0].empty()) return {}; int m = matrix.size(), n = matrix[0].size(), k = 0; vector<int> res(m * n); for (int i = 0; i < m + n - 1; ++i) { int low = max(0, i - n + 1), high = min(i, m - 1); if (i % 2 == 0) { for (int j = high; j >= low; --j) { res[k++] = matrix[j][i - j]; } } else { for (int j = low; j <= high; ++j) { res[k++] = matrix[j][i - j]; } } } return res; } };
下面這種方法就有一點暴力搜索的感受,不像上面一種精確計算每一層的座標範圍,這種方法是利用對角線上的數字的橫縱座標之和恆定這一特性來搜索的,而後把和爲特定值的數字加入結果res中,參見代碼以下:
解法四:
class Solution { public: vector<int> findDiagonalOrder(vector<vector<int>>& matrix) { if (matrix.empty() || matrix[0].empty()) return {}; int m = matrix.size(), n = matrix[0].size(), k = 0; vector<int> res; for (int k = 0; k < m + n - 1; ++k) { int delta = 1 - 2 * (k % 2 == 0); int ii = (m - 1) * (k % 2 == 0); int jj = (n - 1) * (k % 2 == 0); for (int i = ii; i >= 0 && i < m; i += delta) { for (int j = jj; j >= 0 && j < n; j += delta) { if (i + j == k) { res.push_back(matrix[i][j]); } } } } return res; } };
參考資料:
https://discuss.leetcode.com/topic/77866/short-bf-solution
https://discuss.leetcode.com/topic/77865/concise-java-solution/2
https://discuss.leetcode.com/topic/77862/my-8ms-short-solution-9line
https://discuss.leetcode.com/topic/77937/java-15-lines-without-using-boolean