数组理论基础
- 数组是存放在连续内存空间上的相同类型数据的集合。
- 数组下标从0开始。
- 数组内存空间地址连续。
- 删除或添加的时候,需要移动其他数组元素的地址。
- 元素不能直接删除,只能覆盖。对比链表。
- 在二维数组上,c++地址空间连续,Java没有指针,不暴露元素地址,寻址操作完全交给虚拟机,返回的是处理后的数值,没有规则。
704. 二分查找
题目链接:https://leetcode.com/problems/binary-search/
class Solution {
// 左闭右闭
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while (left <= right) { // 边界处理1
int middle = left + ((right - left) >> 1); // 比特右移,相当于
if (nums[middle] > target) {
right = middle -1; // 边界处理2
} else if (nums[middle] < target) {
left = middle + 1; // 边界处理2
} else {
return middle;
}
}
return -1;
}
}
思路:
- 二分查找的前提是 1. 数组为有序数组,2. 数组中无重复元素
- 在while寻找中每一次边界的处理要根据区间的定义来操作,这就是循环不变量规则。
- 两种方法:左闭右闭,左闭右开,着重边界处理1和2
- int middle = left + ((right - left) >> 1); 比特右移,相当于 left + (right -left) /2
- 数学意义:右移一位相当于除2,右移n位相当于除以2的n次方。用来计算区间中间的下标(如果left、right都比较大的情况下,left + right就有可能会溢出)
- 时间复杂度:
O(log n)
空间复杂度:O(1)
27. 移除元素
题目链接:https://leetcode.com/problems/remove-element/
class Solution {
// 快慢双指针
public int removeElement(int[] nums, int val) {
int slowIndex = 0; // 用来定位新数组下标
int fastIndex = 0; // 遍历原数组,寻找不等于val的新数组元素
for (; fastIndex < nums.length; fastIndex++){
if (nums[fastIndex] != val) {
nums[slowIndex++] = nums[fastIndex];
// equals nums[slowIndex] = nums[fastIndex]; slowIndex++;
}
}
return slowIndex;
}
}
思路:
- 数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。
- 双指针(快慢指针):通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
- 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置 - 时间复杂度:
O(n)
空间复杂度:O(1)
class Solution {
// 相向双指针法
public int removeElement(int[] nums, int val) {
int leftIndex = 0;
int rightIndex = nums.length - 1;
while (leftIndex <= rightIndex) {
while (leftIndex <= rightIndex && nums[leftIndex] != val) {
//找到第一个等于val的下标
leftIndex++;
}
while (leftIndex <= rightIndex && nums[rightIndex] == val) {
// 找到右边数第一个不等于val的下标,前移
rightIndex--;
}
// 将右边不等于val的元素覆盖左边等于val的元素
if (leftIndex < rightIndex) {
nums[leftIndex]=nums[rightIndex];
leftIndex ++;
rightIndex --;
}
}
return leftIndex;
}
}