Open yifanzheng opened 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);
}
}
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;
}
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];
}
}
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];
}
}
数组
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。数组由于是紧凑连续存储,可以随机访问,通过索引快速找到对应元素,而且相对节约存储空间。但正因为连续存储,内存空间必须一次性分配够,所以说数组如果要扩容,需要重新分配一块更大的空间,再把数据全部复制过去,时间复杂度 O(N);而且如果想在数组中间进行插入和删除,每次必须搬移后面的所有数据以保持连续,时间复杂度 O(N)。
线性表(Linear List):就是数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。 连续的内存空间和相同类型的数据:使数组具有随机访问能力,但是数组的操作变得低效,比如在数组中删除或插入一个数据,为了保证连续性,就需要做大量的数据搬移工作。
随机访问数组中元素的寻址公式:
练习