加载中…
应用场景:按下标随机访问 · 双指针 · 前缀和
交互式动画演示,可调整参数并单步执行。
全屏打开数组(Array) 是一种用连续内存存储相同类型元素的线性数据结构。它支持通过下标在 O(1) 时间内随机访问任意元素。
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| 按下标访问 | O(1) | 地址 = 基址 + 下标 × 元素大小 |
| 尾部插入/删除 | O(1) | 均摊 |
| 中间插入/删除 | O(n) | 需要移动元素 |
| 查找(无序) | O(n) | 线性扫描 |
| 查找(有序) | O(log n) | 二分查找 |
graph LR A[索引 0] --> B[索引 1] B --> C[索引 2] C --> D[索引 3] D --> E[索引 4]
数组是所有数据结构的基石——栈、队列、堆、哈希表的底层都离不开它。
| 维度 | 数组 | 链表 |
|---|---|---|
| 内存 | 连续,缓存友好 | 分散,缓存不友好 |
| 随机访问 | O(1) | O(n) |
| 头部插入 | O(n) | O(1) |
| 空间开销 | 无额外指针 | 每个节点多存指针 |
| 扩容 | 需要复制(O(n)) | 无需扩容 |
选择原则:
Java ArrayList 默认容量 10,满时扩容为 1.5 倍:
class DynamicArray {
private int[] data;
private int size;
public DynamicArray() {
data = new int[4];
size = 0;
}
public void add(int val) {
if (size == data.length) resize();
data[size++] = val;
}
private void resize() {
int[] newData = new int[data.length * 2];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
public int get(int index) {
if (index < 0 || index >= size) throw new IndexOutOfBoundsException();
return data[index];
}
}public void reverse(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int slow = 0;
for (int fast = 1; fast < nums.length; fast++) {
if (nums[fast] != nums[slow]) {
slow++;
nums[slow] = nums[fast];
}
}
return slow + 1;
}public void rotate(int[] nums, int k) {
int n = nums.length;
k %= n;
reverse(nums, 0, n - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
}
private void reverse(int[] nums, int lo, int hi) {
while (lo < hi) {
int tmp = nums[lo]; nums[lo] = nums[hi]; nums[hi] = tmp;
lo++; hi--;
}
}int[] prefix = new int[n + 1];
for (int i = 0; i < n; i++) {
prefix[i + 1] = prefix[i] + nums[i];
}
// 区间 [l, r] 的和 = prefix[r+1] - prefix[l]// 行优先遍历
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
process(matrix[i][j]);
// 列优先遍历
for (int j = 0; j < n; j++)
for (int i = 0; i < m; i++)
process(matrix[i][j]);public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
int top = 0, bottom = matrix.length - 1;
int left = 0, right = matrix[0].length - 1;
while (top <= bottom && left <= right) {
for (int j = left; j <= right; j++) res.add(matrix[top][j]);
top++;
for (int i = top; i <= bottom; i++) res.add(matrix[i][right]);
right--;
if (top <= bottom)
for (int j = right; j >= left; j--) res.add(matrix[bottom][j]);
bottom--;
if (left <= right)
for (int i = bottom; i >= top; i--) res.add(matrix[i][left]);
left++;
}
return res;
}| 技巧 | 适用场景 | 示例 |
|---|---|---|
| 双指针 | 有序数组、原地操作 | 两数之和、去重 |
| 滑动窗口 | 连续子数组/子串 | 最长无重复子串 |
| 前缀和 | 区间查询 | 子数组和为 K |
| 差分 | 区间修改 | 航班预订 |
| 原地哈希 | 找缺失/重复 | nums[i] 放到索引 i |
public List<Integer> findDisappearedNumbers(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int idx = Math.abs(nums[i]) - 1;
if (nums[idx] > 0) nums[idx] = -nums[idx];
}
List<Integer> res = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) res.add(i + 1);
}
return res;
}left <= right 还是 left < right?画小例子验证。long。public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int need = target - nums[i];
if (seen.containsKey(need)) return new int[]{seen.get(need), i};
seen.put(nums[i], i);
}
return new int[]{};
}