704.二分查找
解题思路
- 数组为有序数组,且数组中无重复元素,所以该题目可用二分法解决
- 二分法解题的关键在于对区间的定义,在写while循环时要注意
- 一般为左闭右闭([left,right])或左闭右开([left,right))
- 左闭右闭情况
右边界
right=numsSize-1
循环条件为
while(left <= right)
当middle的值大于目标值target时,更新左区间的右边界。因为区间是左闭右闭,middle包含在之前的区间里且已经判断完毕,所以更新的右边界应该不包含middle,否则将不满足条件,即
right=middle-1
- 左闭右开情况
右边界
right = numsSize
循环条件为
while (left < right)
if (nums[middle] > target) right 更新为 middle,因为当前nums[middle]不等于target,去左区间继续寻找,而寻找区间是左闭右开区间,所以right更新为middle,即:下一个查询区间不会去比较nums[middle]
right = middle
遇到的问题
- 未考虑到middle=(left+right)/2的越界问题
- 好久没写代码,导致格式上出现一些细节问题,比如nums[middle]而非nums(middle)
代码实现
左闭右闭区间
int search(int* nums, int numsSize, int target){
int left = 0;
int right = numsSize-1;
int middle = 0;
while(left<=right) {
//更新查找下标middle的值
middle = left + (right - left) / 2;
//target可能会在[left,middle-1]区间中
if(nums[middle] > target) {
right = middle-1;
}
//target可能会在[middle+1,right]区间中
else if(nums[middle] < target) {
left = middle+1;
}
//下标元素等于target值时,返回middle
else if(nums[middle] == target){
return middle;
}
}
//未找到,返回-1
return -1;
}
左闭右开区间
int search(int* nums, int numsSize, int target) {
int left = 0;
int right = numsSize;
while(left < right){
int middle = (left + right) / 2;
if(nums[middle] > target){
right = middle;
}
else if(nums[middle] < target){
left = middle + 1;
}
else if(nums[middle] == target){
return middle;
}
}
return -1;
}
总结
今天刚看到这题的时候,第一反应是简单查找,一个一个遍历,但学完二分法后明白那是多复杂的做法,如果给的数据非常多的话,查找起来就会非常困难。
二分法的关键在于区间的定义,在循环中要始终坚持根据查找区间的定义来做边界处理,常用的有左闭右闭和左闭右开两种,需熟悉并彻底掌握。
27.移除元素
解题思路
- 题目要求原地修改,则我们不能重新
new
一个新的数组,而是只能在原数组上进行操作,最后返回一个长度 - 因为数组的元素在内存地址中是连续的,所以不能单独删除数组中的某个元素,只能覆盖
- 暴力解法:用两层for循环,第一个for循环用来遍历数组元素,第二个for循环用来更新数组元素(时间复杂度是O(n^2),空间复杂度:O(1))
- 双指针解法(快慢指针法):通过一个快指针和慢指针在一个for循环下完成两个for循环的工作,快指针用来寻找新数组的元素,慢指针用来更新新数组的下标(时间复杂度:O(n),空间复杂度:O(1))
遇到的问题
- 对双指针具体指的是什么理解了好久
代码实现
暴力求解
int removeElement(int* nums, int numsSize, int val) {
int size = numsSize;
for(int i = 0;i < size;i++){
if(nums[i] == val){
for(int j = i + 1;j < size;j++){
nums[j - 1] = nums[j];
}
i--;
size--;
}
}
return size;
}
双指针求解
int removeElement(int* nums, int numsSize, int val) {
int slow = 0;
for(int fast = 0;fast < numsSize;fast++){
if(nums[fast] != val){
nums[slow] = nums[fast]; //快指针元素挪到慢指针位置
slow++;
}
}
return slow;
}
总结
暴力求解可,双指针更佳。
今日感受
好久没学算法了,一下子感觉要长脑子了。。。今天学起来感觉思路是流畅的,就是代码写起来很困难,要么是格式不记得,要么是没办法写出心中所想,谁懂这种痛苦!!!不过还好今天也算是重新启航了,坚持下去,多刷!!