编程导航算法通关村一不简单的数组增删改查

数组

不要小瞧数组 ,很多边界条件非常复杂,而且很多难题后面都有数组

初始化数组

Java 中有三种方式

  1. int[ ] arr = new int[ ][5]
  2. int[ ] arr = new int[ ]{1, 2, 3, 4, 5}
  3. int[] arr = {1, 2, 3, 4, 5}

推荐使用第三种方式

查找一个元素

    /**
     * 查找一个元素
     * @param arr 数组
     * @param size 已经存放的元素容量
     * @param key  待查找的元素
     * @return
     */
    public static int findByElement2(int[] arr, int size, int key) {
        for (int i = 0; i < size; i++) {
            if (arr[i] == key) {
                return i;
            }
        }
        // 没有找到返回 -1 
        return -1;
    }

增加一个元素

不要小看这个问题,看看着简单做着难

首先理解一下 addByElementSequence 函数传入的 3 个参数

  1. arr 数组
  2. size 数组已经存储的元素数量,从 1 开始编号,实际存储的有效值
  3. element 待插入的元素的值

最重要的是第二个参数是意识,什么是有效值,数组还有无效值码?

先来看看 AI 怎么说 :

数组的有效值是指数组中存储的实际有意义的元素数量。在数组中,可能会分配一定的内存空间,但并不是所有的位置都被实际使用。有效值是指在数组中被赋予了实际意义的元素的数量。通过有效值,我们可以确定数组的实际大小,即存储了多少个元素。有效值通常被记录在一个单独的变量中,比如在给定的代码中使用的 size 变量。 有效值的数量可以是小于或等于数组的容量的。如果有效值数量小于数组的容量,那么数组中剩下的位置可能是未赋值的,默认值取决于数组的类型,,一般我们只会遇到 int 类型

脑子里还是充满了问号 ? 不急看了下面的图秒懂
在这里插入图片描述

接着看第一个判断条件

   if (size >= arr.length) {
       return -1;
   }

为什么 size = arr.length 还需要退出?

因为 arr.length 是数组的 数组的容量 ,如果 size 等于数组的容量就表示,数组此时已经把分配的空间全部使用了,已经没有其其他空间可以插入了。

为什么 index = size ? 等于其他的不行吗 ?

答案肯定是不行啦🤣
解释: 假设 index = 0 如果我要插入是最后一个元素,那么应该是加入到最后一个的就变成插入到第一个了。
还比如 index = size - 1 的话那么,我要插入的最后一个元素就变成插入到倒数第一个了,后面两个循环可能进不去的

最后看一些流程图

注意我标识的 index 位置都是以索引为 1 标注的

测试用例的代码

 public static void main(String[] args) {
        int[] arr = {1, 3, 5, 6, 8, 9, 10};
        int i = addByElementSequence(arr, 5, 0);
        System.out.println(i);
    }

最后关于 两个循环的条件如何判断边界

我自己总结了一下 可以试试 特殊值 比如 index = 0 或者 index = size 这种情况
在这里插入图片描述在这里插入图片描述

具体代码

	/**
     * 将给定的元素插入到有序数组的对应位置中
     *
     * @param arr     数组
     * @param size    数组已经存储的元素数量,从1开始编号,实际存储的有效值
     * @param element 待插入的元素的值
     * @return
     */
    public static int addByElementSequence(int[] arr, int size, int element) {
        // 最后一个就是 size == arr.length
        if (size >= arr.length) {
            return -1;
        }

        int index = size;
		// 遍历整个数组,判断要插入 index 的具体位置,因为要插入到有序列表之中
		// 这里为什么 i 小于 size 次,原因是 element 需要和数组的每一个元素都做比较
        for (int i = 0; i < size; i++) {
            if (element < arr[i]) {
                index = i;
                break;
            }
        }

        // 元素后移
        for (int i = size; i > index ; i--) {
            arr[i] = arr[i - 1];
        }

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

        return index;
    }

删除一个元素

对于删除,不能一边从后向前移动一边查找了,因为元素可能不存在。所以要分为两个步骤,先查是否存
在元素,存在再删除。

注意这里有一个细节
当我们要是删除 最后一个有效值 , 我们发现不会进入 第二个 for 循环,但是最后面有一个 siez-- 把有效值的范围缩小了

    /**
     * 遍历数组,如果发现目标元素,则将其删除,
     * 数组的删除就是从目标元素开始,用后续元素依次覆盖前继元素
     *
     * @param arr  数组
     * @param size 数组中的元素个数
     * @param key  要删除的目标值
     */
    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;
    }

输出数组, 这里就只会输出 有效值

	public static void printList(String msg, int[] arr, int size) {
		System.out.println("\n通过" + msg + "打印");
		   for (int i = 0; i < size; i++) {
		       System.out.print(arr[i] + " ");
		   }
	}

练习

判断是否为单调数列

题目:896. 单调数列

这里涉及到一个点,我们更倾向于用内存换时间、时间换内存 ?

内存换时间

复习一下 || 规则

  1. 如果两个操作数都是 true,则结果为 true。
  2. 如果有一个操作数是 true,则结果为 true。
  3. 如果两个操作数都是 false,则结果为 false

具体代码

class Solution {
    public boolean isMonotonic(int[] nums) {
    	// 认为分割两种情况,需要遍历两次,费内存
        return isSorted(nums, true) || isSorted(nums, false);
    }

    public boolean isSorted(int[] nums, boolean isInc) {
        for (int i = 0; i < nums.length - 1; i++) {
            if (isInc) {
                if (nums[i] > nums[i + 1]) {
                    return false;
                }
            } else {
                if (nums[i] < nums[i + 1]) {
                    return false;
                }
            }
        }
        return true;

    }

只需要遍历一次的写法

class Solution {
    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] > nums[i + 1]) {
                dec = false;
            }
        }
		// 只要有一个是 true那么结果就是 true
        return inc || dec;
    }
}

数组合并专题

题目:88. 合并两个有序数组

算法题目

大概有两种方式

  1. 直接拼接到最后,使用 Arrays.sort() 排序 X
  2. 从后往前两两比较,大的直接就放在后面 √

第一种方式

这种方式主要是锻炼一下边界条件

在这里插入图片描述

	 /**
     * 方法1:先合并再排序实现排序
     *
     * @param nums1     第一个数组
     * @param nums1_len 第一个数组的长度
     * @param nums2     第二个数组,将nums2合并到nums1中
     * @param nums2_len 第二个数组的长度
     */
    public static void merge1(int[] nums1, int nums1_len, int[] nums2, int nums2_len) {
        for (int i = 0; i < nums2_len; i++) {
            nums1[i + nums1_len] = nums2[i];
        }
        Arrays.sort(nums1);
    }

第二种方式

在这里插入图片描述

class Solution {
    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]) {
            	// 如果 num2 的比较大,那么就把 num2 的放到对应的位置
                nums1[i--] = nums1[len1--];
            } else if (nums1[len1] < nums2[len2]) {
                nums1[i--] = nums2[len2--];
            }
        }
		// nums 或者 nums2 还有多余的值那么依次加到数组前面的索引位置就可以了
        while (len1 != -1) {
            nums1[i--] = nums1[len1--];
        }

        while (len2 != -1) {
            nums1[i--] = nums2[len2--];
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值