rokevin
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
移动
前端
语言
  • 基础

    • Linux
    • 实施
    • 版本构建
  • 应用

    • WEB服务器
    • 数据库
  • 资讯

    • 工具
    • 部署
开放平台
产品设计
  • 人工智能
  • 云计算
计算机
其它
GitHub
  • 数组

  • 数组的核心特性
  • Java 数组代码示例
    • 1. 数组的初始化与基本操作
    • 2. 数组的插入与删除(需手动实现)
  • 数组常见算法题(附解析)
    • 1. 两数之和(LeetCode 1)
    • 2. 数组中的第 K 个最大元素(LeetCode 215)
    • 3. 合并两个有序数组(LeetCode 88)
    • 4. 移动零(LeetCode 283)
    • 5. 螺旋矩阵(LeetCode 54)
  • 总结

数组

数组(Array)是最基础的数据结构之一,它是相同类型元素的有序集合,通过索引(下标) 快速访问元素,在内存中占用连续的存储空间。以下从核心特性、Java 代码示例、经典算法题三个方面详解:

数组的核心特性

  1. 固定长度:一旦初始化,长度不可变(Java 中通过 new 初始化时指定长度)。
  2. 连续内存:元素在内存中连续存储,索引从 0 开始,支持 O (1) 时间复杂度的随机访问。
  3. 同类型元素:数组中所有元素必须是同一数据类型(基本类型或引用类型)。
  4. 优缺点:
    • 优点:随机访问效率高,结构简单。
    • 缺点:插入 / 删除元素需移动其他元素(时间复杂度 O (n)),长度固定不灵活。

Java 数组代码示例

1. 数组的初始化与基本操作

public class ArrayDemo {
    public static void main(String[] args) {
        // 1. 声明并初始化(静态初始化:长度由元素个数决定)
        int[] intArray = {1, 2, 3, 4, 5};
        String[] strArray = new String[]{"a", "b", "c"};

        // 2. 动态初始化(指定长度,元素为默认值:int→0,String→null)
        int[] dynamicArray = new int[5]; // 长度5,初始值 [0,0,0,0,0]

        // 3. 访问元素(通过索引,O(1) 时间)
        System.out.println(intArray[2]); // 输出:3(访问索引2的元素)

        // 4. 修改元素
        intArray[2] = 10;
        System.out.println(intArray[2]); // 输出:10

        // 5. 遍历数组
        // 方式1:for循环(适合需要索引的场景)
        for (int i = 0; i < intArray.length; i++) {
            System.out.print(intArray[i] + " "); // 输出:1 2 10 4 5 
        }
        System.out.println();

        // 方式2:增强for循环(适合仅遍历元素,无需索引)
        for (int num : intArray) {
            System.out.print(num + " "); // 输出同上
        }
        System.out.println();

        // 6. 数组长度(length属性,注意无括号)
        System.out.println("数组长度:" + intArray.length); // 输出:5
    }
}

2. 数组的插入与删除(需手动实现)

public class ArrayOperation {
    // 向数组指定索引插入元素(需扩容复制)
    public static int[] insert(int[] arr, int index, int value) {
        if (index < 0 || index > arr.length) {
            throw new IndexOutOfBoundsException("索引越界");
        }
        // 创建新数组(长度+1)
        int[] newArr = new int[arr.length + 1];
        // 复制原数组索引0到index-1的元素
        System.arraycopy(arr, 0, newArr, 0, index);
        // 插入新元素
        newArr[index] = value;
        // 复制原数组index到末尾的元素
        System.arraycopy(arr, index, newArr, index + 1, arr.length - index);
        return newArr;
    }

    // 从数组删除指定索引的元素
    public static int[] delete(int[] arr, int index) {
        if (index < 0 || index >= arr.length) {
            throw new IndexOutOfBoundsException("索引越界");
        }
        // 创建新数组(长度-1)
        int[] newArr = new int[arr.length - 1];
        // 复制原数组索引0到index-1的元素
        System.arraycopy(arr, 0, newArr, 0, index);
        // 复制原数组index+1到末尾的元素
        System.arraycopy(arr, index + 1, newArr, index, newArr.length - index);
        return newArr;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        // 插入:在索引2处插入5 → [1,2,5,3,4]
        int[] inserted = insert(arr, 2, 5);
        // 删除:删除索引3处的元素(3)→ [1,2,5,4]
        int[] deleted = delete(inserted, 3);
    }
}

数组常见算法题(附解析)

1. 两数之和(LeetCode 1)

题目:给定一个整数数组 nums 和目标值 target,返回两个数的索引,使它们的和为 target。

解法:哈希表优化(时间 O (n),空间 O (n))

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[]{map.get(complement), i};
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("无结果");
}

2. 数组中的第 K 个最大元素(LeetCode 215)

题目:在未排序的数组中找到第 k 个最大的元素(要求时间复杂度优于 O (n log n))。

解法:快速选择算法(平均时间 O (n),最坏 O (n²))

public int findKthLargest(int[] nums, int k) {
    k = nums.length - k; // 转换为“第k小”问题(便于快速选择)
    int left = 0, right = nums.length - 1;
    while (left < right) {
        int pivot = partition(nums, left, right);
        if (pivot == k) {
            break;
        } else if (pivot < k) {
            left = pivot + 1;
        } else {
            right = pivot - 1;
        }
    }
    return nums[k];
}

// 快速排序分区函数
private int partition(int[] nums, int left, int right) {
    int pivot = nums[left];
    int i = left, j = right;
    while (i < j) {
        while (i < j && nums[j] >= pivot) j--;
        nums[i] = nums[j];
        while (i < j && nums[i] <= pivot) i++;
        nums[j] = nums[i];
    }
    nums[i] = pivot;
    return i;
}

3. 合并两个有序数组(LeetCode 88)

题目:给两个有序整数数组 nums1(长度 m+n,后 n 位为 0)和 nums2(长度 n),合并 nums2 到 nums1 中,使结果有序。

解法:双指针从后向前遍历(避免覆盖,时间 O (m+n),空间 O (1))

public void merge(int[] nums1, int m, int[] nums2, int n) {
    int i = m - 1, j = n - 1, k = m + n - 1;
    while (i >= 0 && j >= 0) {
        if (nums1[i] > nums2[j]) {
            nums1[k--] = nums1[i--];
        } else {
            nums1[k--] = nums2[j--];
        }
    }
    // 若nums2有剩余元素,直接复制到nums1前面
    while (j >= 0) {
        nums1[k--] = nums2[j--];
    }
}

4. 移动零(LeetCode 283)

题目:将数组中的所有 0 移动到末尾,保持非零元素的相对顺序。

解法:双指针(一次遍历,时间 O (n),空间 O (1))

public void moveZeroes(int[] nums) {
    int index = 0; // 记录非零元素的位置
    // 第一步:将所有非零元素移到前面
    for (int num : nums) {
        if (num != 0) {
            nums[index++] = num;
        }
    }
    // 第二步:剩余位置补0
    while (index < nums.length) {
        nums[index++] = 0;
    }
}

5. 螺旋矩阵(LeetCode 54)

题目:按顺时针螺旋顺序返回矩阵中的所有元素。

解法:模拟边界收缩(时间 O (mn),空间 O (mn))

public List<Integer> spiralOrder(int[][] matrix) {
    List<Integer> res = new ArrayList<>();
    if (matrix == null || matrix.length == 0) return res;
    int top = 0, bottom = matrix.length - 1;
    int left = 0, right = matrix[0].length - 1;
    
    while (true) {
        // 左→右
        for (int i = left; i <= right; i++) res.add(matrix[top][i]);
        if (++top > bottom) break;
        // 上→下
        for (int i = top; i <= bottom; i++) res.add(matrix[i][right]);
        if (--right < left) break;
        // 右→左
        for (int i = right; i >= left; i--) res.add(matrix[bottom][i]);
        if (--bottom < top) break;
        // 下→上
        for (int i = bottom; i >= top; i--) res.add(matrix[i][left]);
        if (++left > right) break;
    }
    return res;
}

总结

数组是算法的基础载体,上述题目涵盖了数组的遍历、查找、插入删除、双指针、边界模拟等核心技巧。掌握数组的特性(尤其是随机访问和连续内存的影响),是解决更复杂数据结构(如链表、栈、队列)问题的前提。实际开发中,Java 的 ArrayList 是数组的动态封装,但其底层仍依赖数组实现,理解数组原理有助于更好地使用集合框架。

最近更新:: 2025/10/27 23:01
Contributors: luokaiwen