704.二分查找
思路:简单的二分噜,通过比较target不断缩小范围直到找到mid
学习:二分使用前提:有序数组【根据是否满足题目的条件来缩小答案所在的区间,这个就是二分的本质】
tips:
-
注意while条件是<=,这影响了下面mid的变化需要多移动一位【不要记太多左闭右开什么的,就记这一个左闭右闭就行】
-
int mid = left+(right-left)>>2; —— 避免溢出,位运算更快
class Solution {
public int search(int[] nums, int target) {
// 加了之后内存更大了,因为这个主要是优化时间的,现在的时间已经不需要优化了
// if (target < nums[0] || target > nums[nums.length - 1]) {
// return -1;
// }
int left = 0, right = nums.length-1;
// 注意这里是<=,因为是可以left == right,所以变的时候需要多移动一位
while(left <= right){
// int mid = (left + right)/2; -- 优化:避免溢出,位运算更快
int mid = left+(right-left) >> 2;
if(nums[mid] > target)
right = mid-1;
else if(nums[mid] < target)
left = mid + 1;
else return mid;
}
return -1;
}
}
27.移除元素
思路:遍历,如果不相等计数器++ ❌——没有考虑到要移除数组,所以要对数组进行改变
学习:原地移除数组,那就是让后面的数据覆盖前面的数据 —— 快慢指针
tips:
- if条件:不相等时直接传进入,相等时进行覆盖操作-也就是不传值不要fast目前的值
- 优化:反向双指针慢:指针从最后移动,如果快指针==val,就把慢指针的值给快指针,同时慢指针--【为了解决同向快慢指针的最坏情况:从头全部移动一遍】
-
为什么返回数值是整数,但输出的答案是数组?——输入数组是以「引用」方式传递的,return的其实就是新数组的长度
-
也可以使用暴力解法:一个for找相同元素,另一个forjin
class Solution {
public int removeElement(int[] nums, int val) {
// v1.0 ❌没有考虑到要移除数组,所以要对数组进行改变
// 首先读题,发现只用返回长度而不用返回具体数据
// 简化一下就是找到这个数组值不为val的次数
// 思路:遍历,如果不相等计数器++
// int cnt = 0;
// for(int num:nums){
// if(num!=val) cnt++;
// }
// return cnt;
// v2.0 双指针✔
// 原地移除数组,那就是让后面的数据覆盖前面的数据 -- 快慢指针
int slow = 0;
for(int fast =0 ;fast<nums.length;fast++){
// 不相等时直接传进入,相等时进行覆盖操作-也就是不传值不要fast目前的值
if(nums[fast]!=val){
nums[slow] = nums[fast];
slow++;
}
}
return slow;
// v3.0 双指针优化✔ 在移除较多元素时更高效 2.0最坏的情况是全部移除
// 思路:这里的慢指针从最后移动,如果快指针==val,就把慢指针的值给快指针,同时慢指针--
int slow =nums.length-1;
// 注意这里的条件是fast和slow的位置,因为末尾我们已经用slow遍历了就不需要再遍历了
for(int fast = 0 ;fast <= slow;fast++){
if(nums[fast]==val){
nums[fast] = nums[slow];
// 注意这里fast也要--,因为要判断从慢指针来的那个是不是也是val
fast--;
slow--;
}
}
return slow + 1;
// 为什么返回数值是整数,但输出的答案是数组?
// 输入数组是以「引用」方式传递的,return的其实就是新数组的长度
}
}