M 数组
2021-01-28 15:15:34 78 庶卒 参与编辑 版本: 2 引用率 62.58%
# 数组

数组是应用最广泛的数据存储结构,他被植入到大部分的编程语言中。数组比较简单,所以用它来作为介绍数据结构的起点。

数组(Array)是有序的元素序列。若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式。这些有序排列的同类数据元素的集合称为数组。

数组是用于储存多个相同类型数据的集合。

## Java中数组的基础知识

声明一个数组就是在内存空间中划出一串连续的空间

数组名代表的是连续空间的首地址,通过首地址可以依次访问数组所有元素,元素在数组中的排序位置叫下标,下标从零开始

**数组长度一旦声明,不可改变不可追加**

声明一个int类型的数组

`int[ ] arr;`或`int arr[ ];`

给数组分配空间

`arr=new int[5];`

给数组赋值
`arr[0]=1;` 0代表的是数组的第1个元素 ,元素下标为0

`arr[1]=1;` 1代表的是数组的第2个元素 ,元素下标为1   

访问数组数据 ,使用数组下标访问 `c=arr[4];`60.93%      
 
 
数组声明缩写
```java
int[] arr={12,3,4,8,5,6,6,7,8,8,9,8};
int []  arr1=new int[ ]{12,3,4,8,5,6,6,4};
```

## 有序数组和无序数组60.86%      

数组根据里面的内容是否有序,分为有序数组和无序数组62.36%      

### 无序数组
- 增:在数组最后插入
- 删:找到元素;改为null;后面的元素逐一前移
- 查:从第一项元素开始遍历,直至找到该元素或者遍历结束

#### 特点
- 效率:插入数据快,查找数据慢,删除数据慢61.18%      
- 扩展性差:一旦创建后,大小就固定了,不能动态扩展数组元素的个数,有可能造成空间浪费或者空间不足。

### 有序数组
- 插入:找到插入元素应该插入的位置(根据元素值的大小);将该位置以及以后的全部数据项向后移动一位;在该位置插入元素
- 删除:找到要删除的元素;后面的所有元素向前移位
- 查找:遍历查找or二分查找

#### 特点
- 效率:插入数据慢,查找数据快(二分查找),删除数据慢。60.00%      
- 扩展性差:一旦创建后,大小就固定了,不能动态扩展数组元素的个数,有可能造成空间浪费或者空间不足。


## 涉及到的算法

### 无序数组转换成有序数组

- 冒泡排序
- 选择排序
- 插入排序
	- 直接插入排序67.08%      
	- 二分插入排序
	- 链表插入排序75.00%      
	- 希尔排序

### 有序数组的查找61.24%      
- 遍历查找
- 二分法查找85.71%      

### 二分查找所需的比较次数

|范围|所需比较次数|
|-|-|
|10|4|
|100|7|
|1000|10|
|10000|14|
|100000|17|
|1000000|20|
|10000000|24|
|100000000|27|
|1000000000|30|

数据范围越大,二分查找体现出来的效率越好

|比较次数(s)|范围(N)|由2的幂表示的范围($2^s$)|
|-|-|-|
|0|1|$2^0$|
|1|2|$2^1$|
|2|4|$2^2$|
|3|8|$2^3$|
|4|16|$2^4$|
|5|32|$2^5$|
|6|64|$2^6$|
|7|128|$2^7$|
|8|256|$2^8$|
|9|512|$2^9$|
|10|1024|$2^10$|

设s表示次数,N表示范围则有如下方程

$N = 2^s$

$s = log_2^N$

查找效率为$O(long^N)$

## 复杂度的大O表示法
- $O(1)$:优秀。例如无序数组插入。
- $O(log^N)$:良好。例如有序的二分查找。
- $O(N)$:及格。例如无序数组的删除,有序数组的删除和插入,线性查找。
- $O(N^2)$:不及格。例如冒泡排序。

## 总结有序数组和无序数组60.86%      

有序数组:插入+ 查找 + 删除 = $O(N) + O(log^N) + O(N)$;

无序数组:插入 + 查找 + 删除 = $O(1) + O(N) + O(N)$;

所以在数据偏向查找操作的时候用有序数组快一些,在数据偏向插入的时候,无序数组好一些。删除操作效率一样

有序数组的最大的好处在于查找的时间复杂度是$O(log^n)$,而无序数组的时间复杂度是$O(n)$。

有序数组的缺点是插入的时间复杂度是$O(n)$,因为值大的元素需要往后移来给新元素腾位置,相反,无序数组的插入时间复杂度是常量$O(1)$



## 相关算法题

### 1 两数之和

在一个数组中找到两个数相加等于指定值,返回这两个值得位置

```java100.00%      
public class Solution {100.00%      
    public int[] twoSum (int[] numbers, int target) {100.00%      
        // write code here100.00%      
        for (int i = 0; i < numbers.length; i++) {
            for (int j = i + 1; j < numbers.length; j++) {100.00%      
                if (numbers[i] + numbers[j] == target) return new int[]{i + 1, j + 1};100.00%      
            }
        }
        return null;
    }
}
```

## 2 返回集合的所有子集100.00%      
```java
import java.util.*;
public class Solution {100.00%      
    public ArrayList> subsets(int[] S) {
        Arrays.sort(S);
        ArrayList> res = new ArrayList<>();100.00%      
        dfs(S, 0, res, new ArrayList<>());100.00%      
        return res;100.00%      
    }
    
    private static void dfs(int[] s, int start, ArrayList> res, ArrayList list) {100.00%      
        if (!res.contains(list)) res.add(new ArrayList<>(list));
        for (int i = start; i < s.length; i++) {100.00%      
            list.add(s[i]);
            dfs(s, i + 1, res, list);100.00%      
            list.remove(list.size() - 1);
        }
    }
}
```

## 3 加起来和为目标值得组合100.00%      
```java
import java.util.*;
public class Solution {100.00%      
    public ArrayList> combinationSum2(int[] num, int target) {100.00%      
        if (num == null || num.length == 0 || target <= 0) return new ArrayList();100.00%      
        Arrays.sort(num);
        ArrayList> res = new ArrayList<>();100.00%      
        dfs(num, target, 0, res, new ArrayList());100.00%      
        return res;100.00%      
    }
    
    private static void dfs(int[] num, int target, int start, ArrayList> res, ArrayList list) {100.00%      
        // 计算和100.00%      
        int sum = 0;100.00%      
        if (list.size() > 0 && !res.contains(list)) {
            for (int i = 0; i < list.size(); i++) {
                sum += list.get(i);
            }
        }
        if (sum == target) res.add(new ArrayList<>(list)); // 命中100.00%      
        else if (sum < target) {100.00%      
            for (int i = start; i < num.length; i++) {67.08%      
                list.add(num[i]); 
                dfs(num, target, i + 1, res, list);100.00%      
                list.remove(list.size() - 1);
            }
        }
    }
}
```

## 4 合并两个有序数组100.00%      
```java
public class Solution {100.00%      
    public void merge(int A[], int m, int B[], int n) {100.00%      
        int res[] = new int[m + n];100.00%      
        int m1 = 0;100.00%      
        int n1 = 0;100.00%      
        while (m1 < m || n1 < n) {100.00%      
            if (m1 >= m) {100.00%      
                res[m1 + n1] = B[n1];100.00%      
                n1++;
            } else if (n1 >= n) {100.00%      
                res[m1 + n1] = A[m1];83.33%      
                m1++; 
            } else if (A[m1] < B[n1]) {
                res[m1 + n1] = A[m1];83.33%      
                m1++;
            } else {100.00%      
                res[m1 + n1] = B[n1];100.00%      
                n1++;
            }
        }
        for (int i = 0; i < m + n; i++) {
            A[i] = res[i];
        }
    }
}
```

## 5 斐波那契数列100.00%      
```java
public class Solution {100.00%      
    // f[0] = 0; f[1] = 1; f[n] = f[n - 1] + f[n - 2]; 100.00%      
    public int Fibonacci(int n) {100.00%      
        if (n <= 1) return n;100.00%      
        int sum = 1;100.00%      
        int one = 0;100.00%      
        for (int i = 2; i <= n; i++) {100.00%      
            // f[n] = f[n - 1] + f[n - 2];
            sum = sum + one;100.00%      
            // f[n - 1] = f[n] - f[n - 2];
            one = sum - one;100.00%      
        }
        return sum;100.00%      
    }
}
```

## 6 螺旋矩阵100.00%      
```java
import java.util.*;
public class Solution {100.00%      
    public ArrayList spiralOrder(int[][] matrix) {
        ArrayList res = new ArrayList<>();98.47%      
        if (matrix.length == 0) return res;
        int top = 0;100.00%      
        int left = 0;100.00%      
        int bottom = matrix.length - 1;100.00%      
        int right = matrix[0].length - 1;100.00%      
        
        while (top <= bottom && left <= right) {100.00%      
            // 1 上面 从左到右100.00%      
            for (int i = left; i <= right; i++) {100.00%      
                res.add(matrix[top][i]);
            }
            // 2 右面 从上到下100.00%      
            for (int i = top + 1; i <= bottom; i++) {100.00%      
                res.add(matrix[i][right]);
            }
            // 3 下面 从右到左 top == botom 时 在步骤1 时已处理过,不在重复处理100.00%      
            for (int i = right - 1; i >= left && top != bottom; i--) {100.00%      
                res.add(matrix[bottom][i]);
            }
            // 4 左面 从下到上 left == right 时 在步骤2时已处理过,不在重复处理100.00%      
            for (int i = bottom - 1; i >= top + 1 && left != right; i--) {100.00%      
                res.add(matrix[i][left]);
            }
            // 一圈走完 全部减1100.00%      
            top++;100.00%      
            right--;100.00%      
            bottom--;100.00%      
            left++;
        }
        return res;100.00%      
    }
}
```

## 7 矩阵查找100.00%      
请写出一个高效的在m*n矩阵中判断目标值是否存在的算法,矩阵具有如下特征:100.00%      
每一行的数字都从左到右排序100.00%      
每一行的第一个数字都比上一行最后一个数字大100.00%      
```java
public class Solution {100.00%      
    /**
     * 
     * @param matrix int整型二维数组 100.00%      
     * @param target int整型 100.00%      
     * @return bool布尔型100.00%      
     */
    public boolean searchMatrix (int[][] matrix, int target) {100.00%      
        // write code here100.00%      
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;100.00%      
        int start = 0;100.00%      
        int end = matrix.length * matrix[0].length - 1;100.00%      
        while (start <= end) {100.00%      
            int mid = start + (end - start) / 2;100.00%      
            int val = matrix[mid / matrix[0].length][mid % matrix[0].length];100.00%      
            if (val == target) return true;100.00%      
            if (val > target) {100.00%      
                end = mid  - 1;100.00%      
            } else {100.00%      
                start = mid + 1;100.00%      
            }
        }
        return false;
    }
}
```

## 8 数组中相加和为0的三元组100.00%      
```java
import java.util.*;
public class Solution {100.00%      
    public ArrayList> threeSum(int[] num) {
        Arrays.sort(num);
        ArrayList> res = new ArrayList<>();100.00%      
        int length = num.length;100.00%      
        for (int i = 0; i < length; i++) {
            // 第一个数 num[i] 第二个数 num[mid] 第三个数 num[right]100.00%      
            int mid = i + 1;100.00%      
            int right = length - 1;100.00%      
            while (mid < right) {100.00%      
                int sum = num[i] + num[mid] + num[right];
                if (sum == 0) {
                    ArrayList temp = new ArrayList<>();100.00%      
                    temp.add(num[i]);
                    temp.add(num[mid]);
                    temp.add(num[right]);
                    res.add(temp);
                    // 去重 mid = mid + 1 时 已经被记录,不能重复记录100.00%      
                    while (mid + 1 < right && num[mid] == num[mid + 1]) mid++;100.00%      
                    // 去重 right = right - 1 时 已经被记录,不能重复记录100.00%      
                    while (right - 1 > mid && num[right - 1] == num[right]) right--;100.00%      
                    mid++;
                    right--;100.00%      
                } else if (sum > 0) {100.00%      
                    // 结果太大100.00%      
                    right--;100.00%      
                } else mid++;  // 结果太小100.00%      
            }
            // 第一个数去重100.00%      
            while (i < length - 2 && num[i + 1] == num[i]) i++;100.00%      
        }
        return res;100.00%      
    }
}
```

## 9 缺失数字100.00%      
```java
import java.util.*;
public class Solution {100.00%      
    public int solve (int[] a) {100.00%      
        // write code here100.00%      
        int target = 0;100.00%      
        int left = 0;100.00%      
        int right = a.length - 1;
        while (left < right) {
            int mid = (right + left) >> 1;100.00%      
            if (mid == a[mid]) left = mid + 1; // 相等 说明不在左边100.00%      
            else if (mid < a[mid]) right = mid; // 小于 说明在左边100.00%      
        }
        return left;
    }
}
```


## 10 在转动过的有序数组中寻找目标100.00%      
```java
public class Solution {100.00%      
    public int search (int[] A, int target) {100.00%      
        // write code here100.00%      
        int left = 0;100.00%      
        int right = A.length - 1;
        while (left <= right) {100.00%      
            int mid = left + (right - left) / 2;100.00%      
            if (A[mid] == target) return mid;100.00%      
            if (A[mid] >= A[left]) {
                // 左侧有序100.00%      
                if (A[mid] > target && A[left] <= target) right = mid - 1;100.00%      
                else left = mid + 1;100.00%      
            } else {100.00%      
                // 右侧有序100.00%      
                if (A[mid] < target && A[right] >= target) left = mid + 1;100.00%      
                else right = mid - 1;100.00%      
            }
        }
        return -1;
    }
}
```

## 11 买卖股票的最好时机100.00%      
```java
public class Solution {100.00%      
    public int maxProfit (int[] prices) {100.00%      
        // write code here100.00%      
        if (prices.length == 0) return 0;
        int min = prices[0];100.00%      
        int max = 0;100.00%      
        for (int i = 1; i < prices.length; i++) {
            min = Math.min(min, prices[i]);100.00%      
            max = Math.max(max, prices[i] - min);100.00%      
        }
        return max;100.00%      
    }
}
```

## 12 两个相等的排序数组中找到上中位数100.00%      
```java
public class Solution {100.00%      
    public int findMedianinTwoSortedAray (int[] arr1, int[] arr2) {100.00%      
        // write code here100.00%      
        int a1 = 0, b1 = 0, mid = arr1.length;100.00%      
        int res = arr1[0] < arr1[0] ? arr1[0] : arr2[0];100.00%      
        while (a1 + b1 < mid) {100.00%      
            if (arr1[a1] < arr2[b1]) res = arr1[a1++];100.00%      
            else res = arr2[b1++];100.00%      
        }
        return res;100.00%      
    }
}
```

## 13 矩阵的最小路径和100.00%      
```java
public class Solution {100.00%      
    public int minPathSum (int[][] matrix) {100.00%      
        // write code here100.00%      
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {100.00%      
                // 第一个数 啥都不做 100.00%      
                if (i == 0 && j == 0) {}100.00%      
                // 第一行100.00%      
                else if (i == 0) matrix[0][j] = matrix[0][j] + matrix[0][j - 1];100.00%      
                // 第一列100.00%      
                else if (j == 0) matrix[i][0] = matrix[i][0] + matrix[i - 1][0];
                else matrix[i][j] += Math.min(matrix[i - 1][j], matrix[i][j - 1]);100.00%      
            }
        }
        return matrix[matrix.length - 1][matrix[0].length - 1];100.00%      
    }
}
```

## 14 数组中未出现的最小正整数100.00%      
```java
public class Solution {100.00%      
    public int minNumberdisappered (int[] arr) {100.00%      
        // write code here100.00%      
        int min = 1;100.00%      
        int index = 0;100.00%      
        while (index < arr.length) {100.00%      
            if (arr[index] == min) {
                min++;
                index = 0;100.00%      
            } else index++;
        }
        return min;100.00%      
    }
}
```

## 15 合并区间100.00%      
```java
public class Solution {100.00%      
    public ArrayList merge(ArrayList intervals) {100.00%      
        intervals.sort((a, b) -> a.start - b.start);
        ArrayList res = new ArrayList<>();86.16%      
        int i = 0;
        int left = 0;100.00%      
        int right = 0;100.00%      
        while (i < intervals.size()) {
            left = intervals.get(i).start;
            right = intervals.get(i).end;
            while (i < intervals.size() - 1 && right >= intervals.get(i + 1).start) {100.00%      
                right = Math.max(right, intervals.get(++i).end);
            }
            res.add(new Interval(left, right));
            i++;
        }
        return res;100.00%      
    }
}
```

## 16 顺时针旋转矩阵100.00%      
```java
public class Rotate {100.00%      
    public int[][] rotateMatrix(int[][] mat, int n) {100.00%      
        // write code here100.00%      
        // 行编号列编号从0开始100.00%      
        // 顺时针 行编号 == 原列编号, 列编号 == 原行数 - 1 - 原行编号 100.00%      
        int res[][] = new int[mat[0].length][mat.length];100.00%      
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat[i].length; j++) {
                res[j][mat.length - 1 - i] = mat[i][j];
            }
        }
        return res;100.00%      
    }
}
```

## 17 数组中的最长连续子序列100.00%      
```java
public class Solution {100.00%      
    public int MLS (int[] arr) {100.00%      
        // write code here100.00%      
        if (arr == null || arr.length == 0) return 0;100.00%      
        Arrays.sort(arr);
        int max = 1;100.00%      
        int temp = 1;100.00%      
        for (int i = 1; i < arr.length; i++) {
            if (arr[i - 1] + 1 == arr[i]) {
                // 满足条件 获取最大值100.00%      
                max = Math.max(max, ++temp);100.00%      
            } else if (arr[i - 1] == arr[i]) continue; // 前后相等 跳过100.00%      
            else temp = 1; // 重新计数100.00%      
        }
        return max;100.00%      
    }
}
```

## 18 寻找最后的山峰100.00%      
山峰元素是指其值大于或等于左右相邻值的元素。给定一个输入数组nums,任意两个相邻元素值不相等,数组可能包含多个山峰。找到索引最大的那个山峰元素并返回其索引。100.00%      
```java
public class Solution {100.00%      
    public int solve (int[] a) {100.00%      
        // write code here100.00%      
        if (a == null || a.length == 0) return -1;100.00%      
        for (int i = a.length - 1; i >= 1; i--) {100.00%      
            if (a[i] >= a[i - 1]) return i;100.00%