数组-数组基础+基础数组LeetCode题目


前言

第二章内容是数组,此系列仅根据我本人学习顺序书写,写这篇文章时,前一章链表还有一些经典LeetCode没有写入博文,但是不影响学习基础的数据结构知识。


1. 数组的概念

数组是线性表结构最基本的结构,特点是元素是一个紧密在一起的序列,相互之间不需要记录彼此的关系就能访问。

什么是线性表???(了解即可)
用通俗易懂的方式来理解,可以将线性表类比成一排排的盒子,每个盒子里放着一个数据元素。这些盒子按照一定的次序排列在一条直线上,每个盒子都有一个编号,可以通过这个编号来找到特定的盒子。而且,每个盒子都有一个左边的盒子和一个右边的盒子,除了最左边的盒子没有左边的盒子,最右边的盒子没有右边的盒子。

这样,线性表就是一个有序的、线性排列的数据集合,它非常适合用来存储一系列有序的数据,比如数组就是线性表的一种常见实现方式。当我们需要按照顺序存储和访问一组数据时,可以使用线性表这种数据结构来帮助我们管理和操作数据。

数组用索引的数字来标识每项数据在数组中的位置,且在大多数编程语言中,索引是从0算起的。我们可以根据数组中的索引快速访问数组中的元素。(老生常谈)
在这里插入图片描述
注意:

  1. 数组从0开始记录,也就是第一个存元素的位置是a[0],最后一个是a[length - 1]。
  2. 数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存(因为普通数组要存放相同类型的元素)。
    在这里插入图片描述
    做题注意事项:
    注意数组空间不一定是满的,100的空间可能只用了10个位置,所以要注意数据个数的变量size和数组长度length可能不一样,解题时注意

1.1 数组存储元素的特征

  1. 创建了一个大小为10的数组,请问此时数组里面是什么?(博主主要学习语言为java,这里只以java为例)
    答: 默认会初始化为0
  2. 是否可以只初始化一部分位置?初始化的本质是什么?
    答: 可以只初始化一部分位置,可以讲前五个位置从小到大下入,后面空着,此时数组内容为{1,2,3,4,5,0,0,0,0,0}。
    初始化的本质就是覆盖已有的值,用你需要的值去覆盖原来的0,因为数组本来是{0,0,0,0,0,0,0,0,0,0},这里只不过被你替换成了{1,2,3,4,5,0,0,0,0,0}。如果此时你想知道有效元素的个数,就必须再使用一个额外的变量,例如size来标记。
  3. 上面已经初始化的元素之间是否可以空着,例如初始化为{1,0,0,4,5,0,2,0,4,0}。其中0位置仍然是未初始化的?
    答: 不可以!!!要初始化,必须从前往后的连续空间初始化,不可以出现空缺的情况,以上提到的情况违背数组的原则。你正在进行某种运算期间可以先给部分位置赋值,而一旦稳定了,就不可以再出现空位置的情况。
  4. 删除元素时,已经被删除的位置该是什么呢?例如原始数组为{1,2,3,4,5,6,7,8,0,0},我删除4之后,根据数组移动的原则,从5开始向前移动,变成{1,2,3,5,6,7,8,?,0,0}
    这里?位置的值为8,这时表示元素数量的size会减一变成7,原来8的位置仍然是8。如果通过size来标记元素数量,最后一个8则不会被访问到

2. 数组-基本操作(CRUD)

大部分题目都是int类型,所以我们用int类型来实现基本功能

2.1 数组创建和初始化

创建一维数组:

int[] arr = new int[10];
//第二种方式
int[] nums = {2,5,0,4,6,-10}; //这种方式背过

初始化数组最基本方式-循环赋值:

for (int i = 0; i < arr.length; i++) {
	arr[i] = i;
}

2.2 增加一个元素

注意边界
推荐实现方式(思考注释中的问题):

/**
     * 
     * @param arr
     * @param size 数组已存储的元素数量,从1开始编号
     * @param element 待插入元素
     * @return
     */
public static int addByElementSequence(int[] arr, int size, int element) {
		// 1.为什么不是size > arr.length?
        if (size >= arr.length) {
            return -1;
        }
		
		// 2.思考为什么不是index = 0 or index = size - 1?
        int index = size;
        //寻找插入位置
        // 3.这里为什么不是 i < size - 1
        for (int i = 0; i < size; i++) {
            if (element < arr[i]) {
                index = i;
                break;
            }
        }

        //元素后移 为什么这里不是 j = size - 1
        for (int j = size; j > index; j--) {
            arr[j] = arr[j - 1]; // index下标开始的元素后移一个位置
        }

        arr[index] = element; //插入数据
        return index;
    }

问题讲解: 时刻注意size是从1开始计数
问题一:size从1开始编号,表示实际元素的个数。而arr.length也是从1开始,当空间满的时候就是size = arr.length,此时就不能再插入元素了。
问题二:如果已有序列{3,4,7,8},如果插入元素大于最大值8,例如9,假如index = 0,最后结果是{9,3,4,7,8}。假如index = size = 1,最后结果就是{3,4,7,9,8}。
问题三:时刻注意size是从1开始编号,请读者根据这个思路思考一下
问题四:size-1(也就是j - 1的位置)是该数组有效元素的最后一个索引,从这里开始让最后一个向后移动一位arr[j] = arr[j-1] 从index这个下标开始的元素向后移动一个位置,如果是j = size - 1,那么就是从index - 1的位置开始向后移动了

2.3 删除一个元素

对于删除,元素会有不存在的情况
分两步,首先是从最左侧开始查是否存在元素,如果元素存在,则从该位置开始执行删除操作。
假如序列是 1 2 3 4 5 6 7 8 9,要删除5,则先遍历,找到5,然后从5开始执行删除操作,也就是从6开始逐步覆盖上一个元素,最终将序列变成 1 2 3 4 6 7 8 9 [9]。
代码:

public static int removeByelement(int arr[], int size, int key) {
        int index = -1;
        for (int i = 0; i < size; i++) {
            if (arr[i] == key) {
                index = i;
                break;
            }
        }
        if (index != -1) {
            for (int i = index + 1; i < size; i++) {
                arr[i - 1] = arr[i];
            }
            size--;
        }
        return size;
    }

3. 算法热身题目—单调数组问题

LeetCode 896 单调数列
如果数组是单调递增或单调递减的,那么它是 单调 的。

如果对于所有 i <= jnums[i] <= nums[j],那么数组nums是单调递增的。 如果对于所有 i <= j,nums[i]> = nums[j],那么数组 nums 是单调递减的。

当给定的数组 nums 是单调数组时返回 true,否则返回 false。
代码(具体的讲解放在注释里了,这题比较基础):

public boolean isMonotonic(int[] nums) {
        boolean inc = true, dec = true;
        for(int i = 0; i < nums.length - 1; i++) {
            if (nums[i] > nums[i + 1]) {
                inc = false;
            }
            if (nums[i + 1] > nums[i]) {
                dec = false;
            }
        }
        return inc || dec;
    }

4. 算法热身题目—数组合并问题

LeetCode88-数组合并
给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 m n ,分别表示 nums1 nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

我们直接使用空间复杂度为O(1)的方式(这是面试常用的)
思路:从后往前插入,A、B元素数量固定,所以排序后最远位置一定是A和B元素都最大的那个,每次找到A或B中最大的那个填入即可
代码:

public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m + n - 1;
        int len1 = m - 1, len2 = n - 1;
        while (len1 >= 0 && len2 >= 0) {
            if (nums1[len1] <= nums2[len2]) {
                nums1[i--] = nums2[len2--];
            } else if (nums1[len1] > nums2[len2]) {
                nums1[i--] = nums1[len1--];
            }
        }

        //若其中一个数组还有值
        while (len1 != -1) {
            nums1[i--] = nums1[len1--];
        }
        while (len2 != -1) {
            nums2[i--] = nums2[len2--];
        }
    }
  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值