1.数组基础结构
由于数组基础结构较为简单,在此略过不谈,只说一下优缺点。
优点:按下标存取数据时时间复杂度为O(1)。
缺点:1)插入和删除时需要移动大量数据; 2)必须在声明是确定数组容量。
2.数组相关的算法
1)线性枚举
例:给定一个长度为n(1≤n≤10⁵)的整型数组,求所有数组元素中最小的值。
思想:非常基础的题,遍历数组即可得到最小值,代码实现如下。
public int findMin(int[] arr){
int min=100000;
//遍历数组
for(int i=0;i<arr.length;i++){
//若找到小于min的值,则赋值给min
if(arr[i]<min){
min = arr[i];
}
}
return min;
}
2)前缀和差分
例:给定一个n(n≤10⁵)个元素的整形数组arr,再给出m(m≤10⁵)次询问,每一次询问都是询问一个区间[l,r],求每次询问的结果。
思想:存储数组每一个下标的前缀和(即前i个元素的和),然后通过sum®-sum(l-1)即可求出每次询问的结果。这就是差分的思想。代码实现如下。
public int[] prefixSum(int[] arr,int m,int[] l,int[] r){
int arrSize = arr.length;
//初始化存储前缀和的数组
int[] sum = new int[arrSize];
//计算前缀和
for(int i=0;i<arrSize;i++){
sum[i] = arr[i];
if(i>0){
sum[i] += sum[i-1];
}
}
int[] res = new int[m];
//计算区间[l,r]的元素和
for(int i=0;i<m;i++){
//防止数组下表越界,l为0是赋值0
int leftsum = l[i]==0?0:sum[l[i]-1];
int rightsum = sum[r[i]];
//差分计算
res[i] = rightsum - leftsum;
}
return res;
}
3)二分查找
例:给定一个n(n≤10⁶)个元素有序整型数组和一个target值,求在O(log₂n)的时间内找到值为target的整型的数组下标,不存在则返回-1。
思想:取数组左端点l=0,右端点r=n-1,生成一个中间点mid=(l+r)/2,并判断mid和target的大小关系,根据大小关系将数组区间折半之后再进行上述操作,直到找到target的值。代码实现如下。
public int binarySearch(int[] arr,int target){
int l = 0;
int r = arr.length-1;
while (true){
//如果左端点大于右端点,说明数组中没有target值,返回-1
if(l>r){
return -1;
}
//取中间点
int mid = (l+r)/2;
//如果中间点的值等于target,则直接返回下标mid
if(arr[mid]==target){
return mid;
}
//如果中间点的值大于target,则取区间[0,mid-1]
if(arr[mid]>target){
r = mid - 1;
}
//如果中间点的值小于target,则取区间[mid+1,arr.length-1]
if(arr[mid]<target){
l = mid + 1;
}
}
}
4)插入排序
例:给定一个n个元素的数组,数组下标从0开始,采用插入排序将数组按照升序排列。
思想:首先将第一个元素和第二个元素比较,如果第二个小于第一个,则将第一个元素向后移动,将第二个元素插入;然后执行第二轮比较,将第三个元素分别与第一个和第二个元素比较,知道前三个元素保持有序;依此类推,知道整个数组变得有序。代码实现如下。
public void insertSort(int[] arr){
int i,j;
for(i=0;i<arr.length;i++){
int x = arr[i];
//用x的值和x前面的数依次比较
for(j=i-1;j>=0;j--){
//如果前面的数大于x,则将前面的数后移
if(x<=arr[j]){
arr[j+1] = arr[j];
}else{
break;
}
}
//循环执行结束或者跳出,说明此时的j+1为x应该在的位置
arr[j+1] = x;
}
for(int n=0;n<arr.length;n++){
System.out.println(arr[n]);
}
}
5)选择排序
例:给定一个n个元素的数组,数组下标从0开始,采用选择排序将数组按照升序排列。
思想:首先遍历数组,找出最小的元素,和第一个元素进行交换;再从第二个元素开始遍历,将最小的元素和第二个元素交换;依此类推,直到整个数组保证从小到大排列。代码实现如下。
public void selectSort(int[] arr){
int temp = 0;
for(int i=0;i<arr.length;i++){
int min = i;
//记录从i到最后一个元素中的最小元素
for(int j=i+1;j<arr.length;j++){
//如果第j个元素小于第min个元素,记录最小元素下标j
if(arr[min]>arr[j]){
min = j;
}
}
//交换第i个元素和min元素
temp = arr[min];
arr[min] = arr[i];
arr[i] = temp;
}
for(int n=0;n<arr.length;n++){
System.out.println(arr[n]);
}
}
6)冒泡排序
例:给定一个n个元素的数组,数组下标从0开始,采用冒泡排序将数组按照升序排列。
思想:首先将第一个元素和第二个元素进行比较,如果第一个大于第二个,则将两个元素交换;然后比较第二个元素和第三个元素,依此类推,可以保证最大的元素被交换到最后的位置;然后进行第二轮比较,保证第二大的元素被交换到倒数第二个位置;一直循环到最后一个元素,完成排序。代码实现如下。
public void bubbleSort(int[] arr){
//共进行arr.length-1轮比较
for(int i=0;i<arr.length-1;i++){
//每轮需要进行的比较次数为arr.length-i-1
for(int j=0;j<arr.length-i-1;j++){
//如果前面的元素大于后面的,则将两个元素交换
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int n=0;n<arr.length;n++){
System.out.println(arr[n]);
}
}
3.习题
文章内容为英雄哥算法星球的个人学习总结,B站英雄哥直播间:https://live.bilibili.com/24513717 ,每日凌晨5点到8点直播刷题。
此文章搬运自个人博客。