計算 2d Java 陣列中對角線值的總和
1. 概述
在 Java 中使用二維數組(2D 數組)很常見,特別是對於涉及矩陣運算的任務。其中一項任務是計算二維數組中對角線值的總和。
在本教程中,我們將探索對二維數組中主對角線和次對角線的值求和的不同方法。
2.問題介紹
首先,讓我們快速了解一下問題。
二維數組形成矩陣。由於我們需要對角線上的元素求和,因此我們假設矩陣為n
x n
,例如 4 x 4 2D 數組:
static final int[][] MATRIX = new int[][] {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 100 }
};
接下來,讓我們澄清一下主對角線和次對角線的含義:
- 主對角線 -對角線從矩陣的左上角延伸到右下角。例如,在上例中,主對角線上的元素為 1、6、11 和 100
- 次對角線 –對角線從右上角延伸到左下角。在同一例子中,4、7、10 和 13 屬於次對角線。
兩條對角線值的總和如下:
static final int SUM_MAIN_DIAGONAL = 118; //1+6+11+100
static final int SUM_SECONDARY_DIAGONAL = 34; //4+7+10+13
由於我們想要建立方法來涵蓋兩種對角線類型,因此讓我們為它們建立一個Enum
:
enum DiagonalType {
Main, Secondary
}
稍後,我們可以將DiagonalType
傳遞給我們的解決方案方法來獲得相應的結果。
3. 辨識對角線上的元素
要計算對角線值的總和,我們必須先辨識對角線上的那些元素。在主對角線的情況下,它非常簡單。當元素的行索引 ( rowIdx
) 和列索引 ( colIdx
) 相等時,此元素位於主對角線上,例如MATRIX[0][0] = 1, MATRIX[1][1] = 6,
以及MATRIX[3][3] = 100
。
另一方面,給定一個n
x n
矩陣,如果一個元素位於次對角線上,則rowIdx + colIdx = n – 1.
, MATRIX[0][3] = 4 (0 + 3 = 4 -1), MATRIX[1][2] = 7 (1 + 2 = 4 – 1),
MATRIX[3][0] = 13 (3 + 0 = 4 -1 )
。因此,我們有**colIdx = n – rowIdx – 1**
。
現在我們了解了對角線元素的規則,讓我們建立計算總和的方法。
4. 循環方法
一個簡單的方法是根據所需的對角線類型循環遍歷行索引,並對元素求和:
int diagonalSumBySingleLoop(int[][] matrix, DiagonalType diagonalType) {
int sum = 0;
int n = matrix.length;
for (int rowIdx = 0; rowIdx < n; row++) {
int colIdx = diagonalType == Main ? rowIdx : n - rowIdx - 1;
sum += matrix[rowIdx][colIdx];
}
return sum;
}
正如我們在上面的實作中所看到的,我們根據給定的diagonalType
計算所需的colIdx
,然後將rowIdx
和colIdx
上的元素新增到sum
變數中。
接下來,我們來測試這個解決方案是否能產生預期的結果:
assertEquals(SUM_MAIN_DIAGONAL, diagonalSumBySingleLoop(MATRIX, Main));
assertEquals(SUM_SECONDARY_DIAGONAL, diagonalSumBySingleLoop(MATRIX, Secondary));
事實證明,該方法對兩種對角線類型的正確值求和。
5. 帶有IntBinaryOperator
物件的DiagonalType
基於循環的解決方案很簡單。然而,在每個循環步驟中,我們必須檢查diagonalType
實例以確定colIdx
,儘管diagonalType
是循環期間不會改變的參數。
接下來,讓我們看看是否可以改進一下。
一種想法是為每個DiagonalType
實例分配一個IntBinaryOperator
對象,以便我們可以計算colIdx
而無需檢查我們擁有哪種對角線類型:
enum DiagonalType {
Main((rowIdx, len) -> rowIdx),
Secondary((rowIdx, len) -> (len - rowIdx - 1));
public final IntBinaryOperator colIdxOp;
DiagonalType(IntBinaryOperator colIdxOp) {
this.colIdxOp = colIdxOp;
}
}
如上面的程式碼所示,我們在DiagonalType Enum
加入了一個IntBinaryOperator
屬性。 **IntBinaryOperation**
是一個函數接口,它接受兩個int
參數並產生一個int
結果。在此範例中,我們使用兩個 lambda 表達式作為Enum
實例的IntBinaryOperator
物件。
現在,我們可以刪除for
迴圈中對角線類型檢查的三元運算:
int diagonalSumFunctional(int[][] matrix, DiagonalType diagonalType) {
int sum = 0;
int n = matrix.length;
for (int rowIdx = 0; rowIdx < n; row++) {
sum += matrix[rowIdx][diagonalType.colIdxOp.applyAsInt(rowIdx, n)];
}
return sum;
}
正如我們所看到的,我們可以透過呼叫applyAsInt()
直接呼叫diagonalType
的colIdxOp
函數來取得所需的**colIdx** .
當然,測試仍然通過:
assertEquals(SUM_MAIN_DIAGONAL, diagonalSumFunctional(MATRIX, Main));
assertEquals(SUM_SECONDARY_DIAGONAL, diagonalSumFunctional(MATRIX, Secondary));
6. 使用串流API
Java 8 中引進了函數式介面。接下來,讓我們使用這兩個 Java 8 功能來解決問題:
public int diagonalSumFunctionalByStream(int[][] matrix, DiagonalType diagonalType) {
int n = matrix.length;
return IntStream.range(0, n)
.map(i -> MATRIX[i][diagonalType.colIdxOp.applyAsInt(i, n)])
.sum();
}
在此範例中,我們將 for 迴圈替換為**IntStream.range()** .
另外, map()
負責將每個索引 ( i
) 轉換為對角線上所需的元素。然後, sum()
產生結果。
最後,這個解決方案也通過了測試:
assertEquals(SUM_MAIN_DIAGONAL, diagonalSumFunctionalByStream(MATRIX, Main));
assertEquals(SUM_SECONDARY_DIAGONAL, diagonalSumFunctionalByStream(MATRIX, Secondary));
與最初的基於循環的解決方案相比,這種方法更加流暢且更易於閱讀。
七、結論
在本文中,我們探討了計算 2D Java 陣列中對角線值總和的不同方法。了解主對角線和次對角線的索引是解決問題的關鍵。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。