1.数组基本操作
1.1数组创建和初始化
int arr = new int[10];
int arr = new int[]{1,2,3};
int arr = {1,2,3};
初始化
for(int i = 0 ; i < arr.length ; i ++)
arr[i] = i;
1.2查找一个元素
/**
* @param size 已经存放的元素个数
* @param key 待查找的元素
*/
public static int findByElement(int[] arr, int size, int key) {
for (int i = 0; i < size; i++) {
if (arr[i] == key)
return i;
}
return -1;
}
1.3插入一个元素
/**
* @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;
//问题②想想这里是否是index=0或者size-1?
int index = size;
//找到新元素的插入位置,问题③ 这里是否应该是size-1?
for (int i = 0; i < size; i++) {
if (element < arr[i]) {
index = i;
break;
}
}
//元素后移,问题④想想这里为什么不是size-1
for (int j = size; j > index; j--) {
arr[j] = arr[j - 1]; //index下标开始的元素后移一个位置
}
arr[index] = element;//插入数据
return index;
}
问题1️⃣:是否应该是size>arr.length?
注意这里的size是从1开始编号的,表示的就是实际元素的个数。而arr.length也是从1开始的,当空间满的时候就是size=arr.length,此时
就不能再插入元素了
问题2️⃣:想想这里是否是index=0或者size-1?
只能令index=size, 0或者size-1都不对。例如已有序列为{3,4,7,8},如果插入的元素比8大,例如9,假如index=0,则最后结果是
{9,3,4,7,8}。假如index=size-1,最后结果就是{3,4,7,9,8}。
问题3️⃣:这里是否应该是size-1?
这里如果是size-1,导致遍历只能到倒数第二位,例如{3,4,7,8},这里size-1=3,i<3则只能遍历到7
问题4️⃣:想想这里为什么不是size-1
如果这里是size-1,会导致把前一位的元素也往后移了
优化:一开始就从后向前一边移动一边对比查找,找到位置直接插入
/**
* @param arr
* @param size 数组已经存储的元素数量,从1开始编号
* @param element 待插入的元素
* @return
*/
public static int addByElementSequence(int[] arr, int size, int element) {
if (size >= arr.length) {
return -1;
}
int index = arr.length - 2;
while (index >= 0 && arr[index] > element) {
arr[index + 1] = arr[index];
index--;
}
arr[index + 1] = element;
return index + 1;
}
1.4删除一个元素
/**
* 从数组中删除元素key
* @param arr 数组
* @param size 数组中的元素个数,从1开始
* @param key 删除的目标值
*/
public 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;
}
2.单调数组
LeetCode 896.判断一个给定的数组是否为单调数组。
分析:如果对于所有 i <= j,A[i] <= A[j],那么数组 A 是单调递增的。 如果对于所有 i <= j,A[i]> = A[j],那么数组 A 是单调递减的。所以遍
历数组执行这个判定条件就行了,由于有递增和递减两种情况。于是我们执行两次循环就可以了,代码如下:
public boolean isMonotonic(int[] nums) {
return isSorted(nums, true) || isSorted(nums, false);
}
public boolean isSorted(int[] nums, boolean increasing) {
int n = nums.length;
for (int i = 0; i < n - 1; ++i) {
if(increasing){
if (nums[i] > nums[i + 1]) {
return false;
}
}else{
if (nums[i] < nums[i + 1]) {
return false;
}
}
}
return true;
}
这样虽然实现功能了,貌似有点繁琐,而且还要遍历两次,能否优化一下呢?假如我们在i和i+1位置出现了nums[i]>nums[i+1],而在另外
一个地方j和j+1出现了nums[j]<nums[j+1],那是不是说明就不是单调了呢?这样我们就可以使用两个变量标记一下就行了,代码如下:
public boolean isMonotonic(int[] nums) {
boolean inc = true, dec = true;
int n = nums.length;
for (int i = 0; i < n - 1; ++i) {
if (nums[i] > nums[i + 1]) {
inc = false;
}
if (nums[i] < nums[i + 1]) {
dec = false;
}
}
return inc || dec;
}
3.数组合并
LeetCode88:给你两个按非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
例子1:
输入: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]
public void merge1(int[] nums1, int nums1_len, int[] nums2, int nums2_len) {
for (int i = 0; i < nums2_len; ++i) {
nums1[nums1_len + i] = nums2[i];
}
Arrays.sort(nums1);
}
但是这么写只是为了开拓思路,面试官会不喜欢,太没技术含量了。这个问题的关键是将B合并到A的仍然要保证有序。因为A是数组不能强行插入,如果从前向后插入,数组A后面的元素会多次移动,代价比较高。此时可以借助一个新数组C来做,先将选择好的放入到C中,最后再返回。这样虽然解决问题了,但是面试官可能会问你能否再优化一下,或者不申请新数组就能做呢?更专业的问法是:上面算法的空间复杂度为O(n),能否有O(1)的方法?
比较好的方式是从后向前插入,A和B的元素数量是固定的,所以排序后最远位置一定是A和B元素都最大的那个,依次类推,每次都找最大的那个从后向前填就可以了,代码如下:
public void merge(int[] nums1, int nums1_len, int[] nums2, int nums2_len) {
int i = nums1_len + nums2_len - 1;
int len1 = nums1_len - 1, len2 = nums2_len - 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--];
}
//假如A或者B数组还有剩余
while (len2 != -1) nums1[i--] = nums2[len2--];
while (len1 != -1) nums1[i--] = nums1[len1--];
}