LeetCode刷題記錄(二)
LeetCode刷題記錄(二)
繼續陣列和字串卡片的題目,這一篇主要介紹一道二維陣列相關的題目。
1、對角線遍歷
題目:
我的思路:
這一題我的思路比較複雜,我先觀察幾種型別的二維陣列
1、 M=N型別的二維陣列,例如:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
它的對角線遍歷值的索引是:
(0, 1)
(0, 1), (1, 0)
(2, 0), (1, 1), (0, 2)
(1, 2), (2, 1)
(2, 2)
2、 對於M<
N型別的二維陣列,例如:
[0, 1, 2, 3]
[4, 5, 6, 7]
它的對角線遍歷值的索引是:
(0, 0)
(0, 1), (1, 0)
(1, 1), (0, 2)
(0, 3), (1, 2)
(1, 3)
3、對於M>
N型別的二維陣列,例如:
[0, 1]
[2, 3]
[4, 5]
[6, 7]
它的對角線遍歷值的索引是:
(0, 0)
(0, 1), (1, 0)
(2, 0), (1, 1)
(2, 1), (3, 0)
(3, 1)
通過比較我們可以發現,第偶數次(從0開始計算)遍歷這個陣列的對角線的時候,遍歷的二維陣列的縱向索引是依次變小的,而它的橫向索引是依次變大的,第奇數次遍歷陣列的對角線的時候,它的縱向索引是依次變大的,而它的橫向索引是依次變小的。因此我們可以這樣做:
- 定義兩個遍歷j和k用於分別表示二位陣列的縱向索引和橫向索引,它們都是從0開始的;
- 依次遍歷二維陣列的對角線,通過觀察,我們可以得到需要遍歷M + N - 1次對角線;
- 當偶數次遍歷對角線的時候,j每次遞減1,k每次遞增1,依次獲得對應索引的數值;
- 當奇數次遍歷對角線的時候,j每次遞增1,k每次遞減1,依次獲得對應索引的數值。
按照這個思路實現的程式碼如下:
class Solution {
public int[] findDiagonalOrder(int[][] matrix) {
if(null == matrix) {
return null;
}
if(matrix.length == 0) {
return new int[]{};
} else {
if(matrix[0].length == 0) {
return new int[] {};
}
}
int i = 0, colLen = matrix.length, rowLen = matrix[0].length;
int j = 0, k = 0, count = 0;
int[] rslt = new int[colLen * rowLen];
while(i < colLen + rowLen - 1) {
//偶數次j變小,k變大
if(i % 2 == 0) {
//防止出現索引為負值的情況
if(j < 0) {
j = 0;
} else if(j > colLen - 1) {
j = colLen - 1;
k++;
}
if(k < 0) {
k = 0;
} else if(k > rowLen - 1) {
k = rowLen - 1;
j++;
}
while(j >= 0 && k < rowLen && count < rslt.length) {
rslt[count] = matrix[j][k];
k++;
//當k遍歷到最大的時候,j不能再減1了,否則下一次將無法從下一位開始
if(k < rowLen) {
j--;
}
count++;
}
i++;
}
//奇數次j變大,k變小
else {
if(j < 0) {
j = 0;
} else if(j > colLen - 1) {
j = colLen - 1;
k++;
}
if(k < 0) {
k = 0;
} else if(k > rowLen - 1) {
k = rowLen - 1;
j++;
}
while(j < colLen && k >= 0 && count < rslt.length){
rslt[count] = matrix[j][k];
j++;
//當j遍歷到最大的時候,k不能再減1了,否則下一次將無法從下一位開始
if(j < colLen) {
k--;
}
count++;
}
i++;
}
}
return rslt;
}
}
反思:
從上面的解法可以看到,這裡程式碼是冗餘的,每次遍歷對角線的時候都有這樣一段程式碼:
if(j < 0) {
j = 0;
} else if(j > colLen - 1) {
j = colLen - 1;
k++;
}
if(k < 0) {
k = 0;
} else if(k > rowLen - 1) {
k = rowLen - 1;
j++;
}
這是用來判斷j和k有沒有遍歷到最前或者最後,如果遍歷到最後需要重置j和k的值以防止出現數組越界的情況。
另外在判斷j和k有沒有遍歷到最後的時候還將另外一個索引加1,這是因為有可能出現j或者k遍歷到最後了,但是另一個索引還未到最後的情況,這時候就需要從另一個索引的下一位開始繼續遍歷,例如:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
陣列已經遍歷到(0, 2)也就是3的時候接下來就需要從6開始遍歷了,這時候就需要將j加1,從(1, 2)開始遍歷。而之所以每個遍歷判斷裡都增加這個語句主要還是方便理解這段程式碼用的,完全可以將它們單獨抽出來簡化程式碼。
另外在遍歷陣列中的數的時候,我還增加了一個判斷,例如:
if(k < rowLen) {
j--;
}
或者
if(j < colLen) {
k--;
}
原先是沒有這個判斷的,直接使用j–或者k–,這是在測試的時候發現的問題,以下面這個陣列為例:
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
當遍歷到(2, 1)即8的時候,這時候j++得到3,k–得到0,跳出迴圈,再次遍歷對角線的時候,j會置為2,k會加1變為1,這時候獲取到的仍然是(2, 1),這樣仍然得到的是8,這就不正確了,這還是因為k沒有向前移一位導致的。因此我增加了一個判斷,當j或者k遍歷到最大的時候,另一個索引保持不變,以便在下次遍歷對角線的時候另一個索引向後移一位。
總的看來,這一道題目我的解法是複雜的,雖然想法比較簡單,但是真正執行的時候會出現很多問題,需要仔細考慮才能夠真正執行通過,我也會繼續尋找更好地解決方案。