理论基础
1. 数组在内存中的存储方式:数组是 存放在 连续内存空间上的 相同类型 数据 的集合。
2. 数组可通过下标索引获取到下标对应的数据,如图:
- 下标从0开始
- 内存地址连续 ----> 插入/删除元素时需要移动其他元素地址
3. 数组元素不能删,只能覆盖。
4. 二维数组在内存的空间地址是否连续?
C++是,Java不一定。
704 二分查找
主要的两个问题:
1. while循环中left < / <= right?
2. nums[middle]>target时,right = middle / middle - 1?
区间搜索中,需要确定的区间定义:
[]
[)
主要是上面两种,也有(]
区间定义,为循环不变量,循环期间,一直不变的原则。
1. []写法:
左右边界:
left=0;
right=nums.size-1;
while循环:
while(left <= right) 合法区间 {
middle=(left+right)/2;
if(nums[middle]>target){ middle一定不是要搜索的值
right=middle-1;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;
2. [)写法:
不包含right
左右边界:
left=0;
right=nums.size;
while循环:
while(left < right) 合法区间 {
middle=(left+right)/2;
if(nums[middle]>target){ 开区间取不到
right=middle;
}else if(nums[middle]<target){
left=middle+1;
}else{
return middle;
}
}
return -1;
补充:
1. 区间概念:二分查找是通过在变换区间里比较来查找target的;
2. 对边界的处理(右开/右闭),用于确定循环不变量;
3. 中点防溢;🌼
(left + right)/2
当 left
和 right
都是较小的正整数时,left + right
可能会导致整数溢出。但是,如果 left
和 right
都是正整数,并且他们的和不会导致溢出,那么 (left + right) / 2
就是一个有效的计算方式。
left + (right - left)/2
- 这种方式首先计算了
right - left
,这是一个正数。因为right
大于等于left
,所以right - left
不会导致溢出。 - 计算
left + (right - left)
不会导致溢出,因为right - left
是一个小于right
的正整数,加上left
不会使结果溢出。
4. 中点偏左/偏右?偏左
27 移除元素
内存地址连续 ----> 插入/删除元素时需要移动其他元素地址
数组元素不能删,只能覆盖。
erase函数复杂度O(n)
暴力解法
两层for循环,一层遍历数组,一层更新数组。
双指针法(快慢指针)
快指针fast:指向新数组中需要的元素
慢指针slow:新数组的下标索引
slow=0;
for(fast=0; fast<nums.size; fast++){
if(nums[fast]!=val){ 更新数组
nums[slow]=nums[fast];
solw++;
}
}
return slow;
slow++可以直接放在nums[slow++]中.