【算法和数据结构】数组

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.习题

1)2319. 判断矩阵是否是一个 X 矩阵

2)599. 两个列表的最小索引总和

3)674. 最长连续递增序列

4)989. 数组形式的整数加法

文章内容为英雄哥算法星球的个人学习总结,B站英雄哥直播间:https://live.bilibili.com/24513717 ,每日凌晨5点到8点直播刷题。
此文章搬运自个人博客。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值