yifanzheng / leetcode-java

数据结构与算法学习
MIT License
3 stars 0 forks source link

数组 #9

Open yifanzheng opened 2 years ago

yifanzheng commented 2 years ago

数组

数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。数组由于是紧凑连续存储,可以随机访问,通过索引快速找到对应元素,而且相对节约存储空间。但正因为连续存储,内存空间必须一次性分配够,所以说数组如果要扩容,需要重新分配一块更大的空间,再把数据全部复制过去,时间复杂度 O(N);而且如果想在数组中间进行插入和删除,每次必须搬移后面的所有数据以保持连续,时间复杂度 O(N)。

线性表(Linear List):就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。 连续的内存空间和相同类型的数据:使数组具有随机访问能力,但是数组的操作变得低效,比如在数组中删除或插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。

随机访问数组中元素的寻址公式:

a[i]_address = base_address + i * data_type_size

练习

yifanzheng commented 2 years ago

实现一个动态扩容的数组

/**
 * 自定义数组
 * <p>
 * 1. 支持动态扩容;
 * 2. 支持根据数组下标进行随机访问操作;
 *
 * @author star
 */
public class Array<T> {
    /**
     * 整型data保存数据
     */
    private T[] data;

    /**
     * 数组容量
     */
    private int capacity;

    /**
     * 数组实际大小
     */
    private int size;

    public Array(int capacity) {
        this.data = (T[]) new Object[capacity];
        this.capacity = capacity;
        // 初始大小为 0,即没有数据
        this.size = 0;
    }

    public Array() {
        // 默认容量 10
        this(10);
    }

    public int size() {
        return size;
    }

    public int capacity() {
        return capacity;
    }

    public T get(int index) {
        checkIndex(index);
        return data[index];
    }

    /**
     * 在数组末尾添加元素
     *
     * @param elem 元素
     */
    public void add(T elem) {
        add(size, elem);
    }

    /**
     * 在指定下标处添加元素
     *
     * @param index 下标
     * @param elem  元素
     */
    public void add(int index, T elem) {
        checkIndexForAdd(index);
        // 如果当前数组大小与容量相同,则进行扩容
        if (size == capacity) {
            // 扩容为原来的 2 倍
            growSize(capacity << 1);
        }
        int numMoved = size - index;
        System.arraycopy(data, index, data, index + 1, numMoved);
        data[index] = elem;
        size++;
    }

    /**
     * 删除并返回元素
     *
     * @param index 下标
     * @return 返回删除的元素
     */
    public T remove(int index) {
        checkIndex(index);
        T removed = data[index];
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            System.arraycopy(data, index + 1, data, index, numMoved);
        }
        data[--size] = null;

        return removed;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(String.format("Array size = %d, capacity = %d \n", size, data.length));
        builder.append('[');
        for (int i = 0; i < size; i++) {
            builder.append(data[i]);
            if (i != size - 1) {
                builder.append(", ");
            }
        }
        builder.append(']');
        return builder.toString();
    }

    private void checkIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
    }

    private void checkIndexForAdd(int index) {
        if (index < 0 || index > size) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
    }

    private void growSize(int newCapacity) {
        this.capacity = newCapacity;
        data = Arrays.copyOf(data, newCapacity);
    }
}
yifanzheng commented 2 years ago

合并两个有序数组

letcode 地址:88.合并两个有序数组

题解

1.最简单得做法是,直接合并数组,然后利用 Arrays.sort() 进行排序。

2. 双指针解法

public static int[] merge(int[] nums1, int m, int[] nums2, int n) {
    int[] nums = new int[m + n];
    int p1 = 0, p2 = 0, index = 0;
    while (p1 < m || p2 < n) {
        // 当 p == m,说明只有 nums2 还没有遍历完成
        if (p1 == m) {
            nums[index++] = nums2[p2++];
            continue;
        }
        // 当 q == n,说明只有 nums1 还没有遍历完成
        if (p2 == n) {
            nums[index++] = nums1[p1++];
            continue;
        }
        if (nums1[p1] < nums2[p2]) {
            nums[index++] = nums1[p1++];
        } else {
            nums[index++] = nums2[p2++];
        }
    }
    return nums;
}
yifanzheng commented 2 years ago

区域和检索 - 数组不可变

LeetCode 地址:303. 区域和检索 - 数组不可变

题解

方法一:依次遍历区域间的元素并相加

class NumArray {

    private int[] data;

    public NumArray(int[] nums) {
        this.data = nums;
    }

    public int sumRange(int left, int right) {
        int sum = 0;
        for (int i = left; i <= right; i++) {
            sum += data[i];
        }
        return sum;
    }
}

方法二:利用分治思想,进行归并相加 效率好像并没有提升,很尴尬。

class NumArray {

    private int[] data;

    public NumArray(int[] nums) {
        this.data = nums;
    }

    public int sumRange(int left, int right) {
        return sum(data, left, right);
    }

    private int sum(int[] data, int left, int right) {
        if (left > right) {
            return 0;
        }
        if (left == right) {
            return data[left];
        }
        int mid = (right - left) / 2 + left;
        return sum(data, left, mid) + sum(data, mid + 1, right);
    }
}

方法三:前缀和思想(最优解)

class NumArray {

    private int[] preNums;

    public NumArray(int[] nums) {
        int len = nums.length;
        preNums = new int[len + 1];
        // 便于累加求和
        preNums[0] = 0;
        // 构建前缀和数组
        for (int i = 0; i < len; i++) {
            preNums[i + 1] = preNums[i] + nums[i];
        }
    }

    public int sumRange(int left, int right) {
        return preNums[right + 1] - preNums[left];
    }
}
yifanzheng commented 2 years ago

二维区域和检索 - 矩阵不可变

LeetCode 地址:二维区域和检索 - 矩阵不可变

class NumMatrix {

    private int[][] preSum;

    public NumMatrix(int[][] matrix) {
        int lenx = matrix.length;
        if (lenx == 0) {
            return;
        }
        int leny = matrix[0].length;
        preSum = new int[lenx + 1][leny + 1];
        for (int i = 1; i <= lenx; i++) {
            for (int j = 1; j <= leny; j++) {
                preSum[i][j] = preSum[i - 1][j] + preSum[i][j - 1] - preSum[i - 1][j - 1] + matrix[i - 1][j - 1];
            }
        }
    }

    public int sumRegion(int row1, int col1, int row2, int col2) {
        return preSum[row2 + 1][col2 + 1] - preSum[row1][ col2 + 1] - preSum[row2 + 1][ col1] + preSum[row1][col1];
    }
}