一、数组理论基础
数组是存放在连续内存空间上的相同类型数据的集合;
数组的索引是从0开始的;
数组的内存空间是一致的,因此在删除或者添加元素的时候,就难免要移动其他元素的地址;
数组的元素是不能删的,只能覆盖
二、二分查找
力扣题目链接:704.二分查找
思路:自己做这道题的时候,首先用了遍历的方法,时间复杂度为O(n);看了讲解之后,发现此题具备二分法的前提条件(有序数组,数组中无重复元素),因此使用二分法更好,可将时间复杂度降为O(logn)
//二分法
//时间复杂度:O(logn); 空间复杂度:O(1);
class Solution {
public int search(int[] nums, int target) {
// 避免当 target 小于nums[0] nums[nums.length - 1]时多次循环运算
if (target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0, right = nums.length - 1;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1;
else if (nums[mid] > target)
right = mid - 1;
}
return -1;
}
}
注意:
1.根据左闭右闭来做边界处理;
2.使用left + ((right - left) >> 1),而不用(left+right)/2的原因:首先>>是右移符号,表示除以2,left + right 在某种情况下可能会超过基本类型所能容纳的最大值(溢出),所以使用left + (right -left) / 2);而且 >> (位运算) 比 / 运算要快所以又left + ((right -left) >> 1) 。(在运算中,加减乘速度一类,除 比较慢,因此在除以2或者除以4的时候使用>>更好一点,<<是乘没变化)
三、移除元素
力扣题目链接:27.移除元素
//暴力解法
//时间复杂度:O(n^2)
class Solution {
public int removeElement(int[] nums, int val) {
int len = nums.length;
for(int i = 0; i < len; i++){
if(nums[i] == val){
for(int j = i; j < len - 1; j++){
nums[j] = nums[j+1];
}
i--;
len--;
}
}
return len;
}
}
双指针法(快慢指针法):通过一个快指针和一个慢指针完成两个for循环的工作。
快指针:寻找新数组的元素,新数组就是不含有目标元素的数组;
满指针:指向更新 新数组下标的位置
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public int removeElement(int[] nums, int val) {
// 快慢指针
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
if (nums[fastIndex] != val) {
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
}
//时间复杂度:O(n)
//空间复杂度:O(1)
//相向双指针法
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length - 1;
while(right >= 0 && nums[right] == val) right--; //将right移到从右数第一个值不为val的位置
while(left <= right) {
if(nums[left] == val) { //left位置的元素需要移除
//将right位置的元素移到left(覆盖),right位置移除
nums[left] = nums[right];
right--;
}
left++;
while(right >= 0 && nums[right] == val) right--;
}
return left;
}
}