数组
不要小瞧数组
,很多边界条件非常复杂,而且很多难题后面都有数组
初始化数组
在 Java
中有三种方式
- int[ ] arr = new int[ ][5]
- int[ ] arr = new int[ ]{1, 2, 3, 4, 5}
- 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 个参数
- arr 数组
- size 数组已经存储的元素数量,从
1
开始编号,实际存储的有效值
- 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. 单调数列
这里涉及到一个点,我们更倾向于用内存换时间、时间换内存 ?
内存换时间
复习一下 || 规则
- 如果两个操作数都是 true,则结果为 true。
- 如果有一个操作数是 true,则结果为 true。
- 如果两个操作数都是 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. 合并两个有序数组
大概有两种方式
- 直接拼接到最后,使用 Arrays.sort() 排序 X
- 从后往前两两比较,大的直接就放在后面 √
第一种方式
这种方式主要是锻炼一下边界条件
/**
* 方法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--];
}
}
}