陣列是 Java 中最基礎、最高效的資料結構。無論是演算法面試、業務邏輯處理,還是框架底層原始碼,陣列操作無處不在。本文將通過三大經典案例——陣列反轉、最值查找、二分搜尋,由淺入深講解核心技巧與避坑指南。
核心思想:雙指針對稱交換,只需遍歷一半長度。
public class ArrayReverse {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
reverse(arr);
System.out.println(Arrays.toString(arr)); // [9, 8, 7, 6, 5, 4, 3, 2, 1]
}
public static void reverse(int[] arr) {
// 邊界防護
if (arr == null || arr.length <= 1) return;
for (int i = 0; i < arr.length / 2; i++) {
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
}
}
IntStream.range(0, arr.length).map(i -> arr[arr.length - 1 - i]).toArray()(會建立新陣列)Collections.reverse(Arrays.asList(arr)) 僅適用於物件陣列(如 Integer[])關鍵細節:初始值必須取陣列首元素,而非 0,否則陣列全為負數時會出錯。
public class MinMaxFinder {
public static void main(String[] args) {
int[] data = {2, 92, 34, 54, 28, -5, -100};
System.out.println("最小值: " + findMin(data)); // -100
System.out.println("最大值: " + findMax(data)); // 92
}
public static int findMin(int[] arr) {
if (arr == null || arr.length == 0) throw new IllegalArgumentException("陣列不能為空");
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) min = arr[i];
}
return min;
}
public static int findMax(int[] arr) {
if (arr == null || arr.length == 0) throw new IllegalArgumentException("陣列不能為空");
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) max = arr[i];
}
return max;
}
}
public static int[] findMinMax(int[] arr) {
int min = arr[0], max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) min = arr[i];
else if (arr[i] > max) max = arr[i]; // else if 減少比較次數
}
return new int[]{min, max};
}
時間複雜度 O(log n),是海量資料查找的首選。提供兩種經典寫法對比。
public static int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1); // 防止溢出
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1; // 未找到
}
public static int binarySearchLeftClosed(int[] arr, int target) {
int left = 0, right = arr.length; // right 不包含
while (left < right) {
int mid = left + ((right - left) >> 1);
if (arr[mid] == target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid; // right = mid,不包含 mid
}
return -1;
}
left + (right - left) / 2 或 (left + right) >> 1,防止 left + right 整數溢出。left = mid + 1 / right = mid - 1(閉區間)或 right = mid(左閉右開),邏輯必須自洽。// 查找第一個 >= target 的位置(下界)
public static int lowerBound(int[] arr, int target) {
int left = 0, right = arr.length;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (arr[mid] >= target) right = mid;
else left = mid + 1;
}
return left;
}
// 查找第一個 > target 的位置(上界)
public static int upperBound(int[] arr, int target) {
int left = 0, right = arr.length;
while (left < right) {
int mid = left + ((right - left) >> 1);
if (arr[mid] > target) right = mid;
else left = mid + 1;
}
return left;
}
| 操作 | 時間複雜度 | 空間複雜度 | 核心關鍵點 |
|---|---|---|---|
| 陣列反轉 | O(n) | O(1) | 雙指針對稱交換,遍歷長度一半 |
| 最值查找 | O(n) | O(1) | 初始值取 arr[0],單次遍歷可同時求 min/max |
| 二分搜尋 | O(log n) | O(1) | 前提有序,防溢出中間值,邊界收縮邏輯自洽 |
掌握這三大核心操作,不僅能應對面試高頻考點,更能在日常開發中寫出高效、健壯的陣列處理代碼。