704 二分查找
解题思路
折半查找思路:
首先要确定边界 这里写的是左闭右闭(左右边界都能取到)
定义左右指针left、right记录查找范围,中间指针mid比较target值
- target < nums[mid],查找值小于中间值,右指针等于中间值-1,right = mid - 1;
- target > nums[mid],查找值大于中间值,左指针等于中间值+1,left = mid + 1;
- target == nums[mid],查找值就是中间值,返回中间值下标;
- 否则返回-1。
注意:
- 如果左闭右开的话[left,right) 循环的边界的是while(l<r);因为让left==right没有意义;例如[1,1)。
- 此时右边界的值取不到,修改时应注意r=mid;
// 时间复杂度:O(n^2) 空间复杂度:O(1)
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size()-1; //左右都闭
while(left <= right){
int mud = (right - left)/2 + left; // 防止溢出 等同于(left + right)/2
if(nums[mud] == target){
return mud;
}
else if (nums[mud] > target){
right = mud-1; // right的值不包括中间人
}
else {
left = mud+1;
}
}
return -1;
}
};
收获
其实主要就是对区间的定义没有理解清楚,在循环中没有始终坚持根据查找区间的定义来做边界处理。
区间的定义就是不变量,那么在循环中坚持根据查找区间的定义来做边界处理,就是循环不变量规则。
27、移除元素
解题思路
暴力法
// 暴力法
// 时间复杂度:O(n^2) 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for(int i = 0;i < size;i++){
if( nums[i] == val){ // 发现需要移除的元素,就将数组集体向前移动一位
for(int j = i+1; j < size; j++){
nums[j-1] = nums[j];
}
size--;
i--; // 因为下表i以后的数值都向前移动了一位,所以i也向前移动一位
}
}
return size;
}
};
双指针
定义两个指针,一个快指针一个慢指针。快指针遍历旧数组,慢指针只在没有查询到所需元素时++,然后进行赋值操作
// 时间复杂度:O(n)O(n) 空间复杂度:O(1)O(1)
class Solution {
public int removeElement(int[] nums, int val) {
int fast = 0;
int slow = 0;
for(;fast<nums.length;fast++){
if(nums[fast]!=val){
nums[slow++] = nums[fast];
}
}
return slow;
}
}
收获
快慢双指针,两个指针从同一位置出发(数组头部)。检查快指针的值是否是需要删除的数值,如果不是:快指针指向的值赋值给慢指针,快指针++,慢指针++。如果是:快指针++。直到快指针到数组结尾。此时返回慢指针的值就是删除操作后的数组长度。