Java 中檢查兩個二維數組是否相等
一、簡介
在本教程中,我們將探討如何在 Java 中檢查兩個二維數組是否相等。首先,我們將回顧並探索該問題以更好地理解它。這樣,我們也將了解常見的陷阱以及處理類似問題時應注意的事項。
然後,我們將採用一種簡單的方法來更好地理解這些概念。之後,我們將開發一種不同的演算法。此外,我們將了解如何在不使用太多資源的情況下解決此問題。因此,了解如何正確比較二維數組不僅僅是解決程式設計問題。
2. 問題定義
比較二維數組在軟體開發的各個領域都非常重要。以下是一些使用二維數組的域:
- 影像處理(電腦視覺和影像處理)
- 遊戲開發(代表遊戲板、地圖或基於圖塊的世界)
- 人工智慧(機器學習演算法 - 神經網路)
- 安全性和加密(一些加密演算法使用位元組或整數的二維數組)
比較 2D 陣列比比較 1D 陣列更具挑戰性。與一維數組不同,二維數組需要我們同時匹配行和列。因此,這又增加了一層複雜性。
此外,我們需要考慮效能——簡單的方法通常是資源密集的,尤其是對於較大的陣列。
最後,二維數組是嵌套資料結構,意味著程式碼更加複雜,出錯的可能性也會增加。
首先,假設我們有兩個二維數組,其中有m
行和n
列。附帶說明一下,在演算法中,我們通常使用m
和n
分別指涉行和列。現在,要認為這兩個數組相等,需要滿足多個條件:
- 它們必須具有相同的行數
m
- 它們必須具有相同的列數
n
- 每個
i
和j
對應元素 (arr1[i][j], arr2[i][j]) 需要相等 - 特別注意事項:處理
null
值和對象
3. 幼稚的方法
通常,我們會使用Arrays.deepEquals()
方法。當我們需要開箱即用的解決方案時,此解決方案非常有用。在我們的例子中,其複雜度與下面的方法相同, O(m*n).
解決這個問題的另一種方法自然是我們能想到的第一種方法。因此,我們將遍歷每個陣列並將每個元素與其對應的元素進行比較。
首先,讓我們看看這個解決方案是什麼樣的,然後我們將更詳細地探討它:
public static boolean areArraysEqual(int[][] arr1, int[][] arr2) {
if (arr1 == null || arr2 == null || arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
// check if rows have different lengths
if (arr1[i] == null || arr2[i] == null || arr1[i].length != arr2[i].length) {
return false;
}
for (int j = 0; j < arr1[i].length; j++) {
if (arr1[i][j] != arr2[i][j]) {
return false;
}
}
}
return true;
}
正如我們所看到的,我們在循環中使用循環。這意味著時間複雜度(大 O 表示法)將為O(m*n)
其中m
和n
分別表示行數和列數。此外,空間複雜度將為O(1)
因為解決此問題所需的記憶體不會隨著輸入大小的增加而增加。
這種方法的優點是:
- 易於理解和實施
- 適用於各種大小的陣列(鋸齒狀數組)
- 一旦發現第一個差異就立即停止
缺點是:
- 時間複雜度差
- 未最佳化
一個重要的方面是我們在處理物件時需要改變我們的方法。首先, !=
比較不適用於物件。其次,我們需要使用equals()
方法並確保我們正在比較的物件已覆寫此方法。最後,我們還需要考慮null
值。
4. 高效率的解決方案
現在,讓我們考慮另一個解決方案。這個解決方案對於大型數組很有用,我們可以接受兩個數組之間的一些差異。
首先,我們需要兩個double
參數,我們將它們命名為similarityThreshold
和samplingWeight.
將similarityThreshold
設為較高的值允許較少的不同元素,而較小的值則允許更多的不同元素。另一方面, samplingWeight
使我們能夠控制要執行的比較的數量。
當samplingWeight
設定為最大值時,此解決方案在最壞情況下與樸素O(m*n)
**方案的時間複雜度*相同,均為 O(m\n)。最大值為1
,代表 100%,所有元素都會進行比較。
現在,讓我們看看我們的演算法。首先,我們進行一些基本檢查,看看引用是否指向同一個物件、是否為null,
或具有不同的長度:
public static boolean areArraysEqual(int[][] arr1, int[][] arr2, double similarityThreshold, double samplingWeight) {
if (arr1 == null || arr2 == null || arr1.length != arr2.length ||
arr1[0].length != arr2[0].length || samplingWeight <= 0 || samplingWeight > 1) {
return false;
}
int similarElements = 0;
int checkedElements = 0;
接下來,我們根據採樣權重計算採樣步長:
int step = Math.max(1, (int)(1 / samplingWeight));
// Iterate through the arrays using the calculated step
for (int i = 0; i < arr1.length; i += step) {
for (int j = 0; j < arr1[0].length; j += step) {
if (Math.abs(arr1[i][j] - arr2[i][j]) <= 1) {
similarElements++;
}
checkedElements++;
}
}
使用它,演算法知道在執行下一次比較之前要跳過多少個元素。這意味著samplingWeight
越小,演算法速度越快。然而,這裡的缺點是samplingWeight
越小,跳過不同元素的機會就越大。
最後,我們將檢查到的元素識別出的相似元素相除,計算相似度,並與先前設定的閾值進行比較:
return (double) similarElements / checkedElements >= similarityThreshold;
}
5. 結論
在本文中,我們了解如何在 Java 中比較兩個二維數組。 此外,我們了解了這種比較的重要性及其在各個領域的用途。
我們看到,最簡單、最安全的方法是比較每個位置的每個元素或使用Arrays.deepEquals()
方法。這些解決方案具有最高的精度,但在陣列相同時執行的步驟也最多。
接下來,我們看到了一種不同的解決方案,適用於更大的資料集。此解決方案速度更快,但精度較差。由我們決定哪種解決方案適合我們的需求。
與往常一樣,程式碼可以在 GitHub 上取得。