代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素

704.二分查找

704. 二分查找 - 力扣(LeetCode)

解题思路

  • 数组为有序数组,且数组中无重复元素,所以该题目可用二分法解决
  • 二分法解题的关键在于对区间的定义,在写while循环时要注意
  • 一般为左闭右闭([left,right])或左闭右开([left,right))
  1. 左闭右闭情况

    右边界

    right=numsSize-1

    循环条件为

    while(left <= right)

    当middle的值大于目标值target时,更新左区间的右边界。因为区间是左闭右闭,middle包含在之前的区间里且已经判断完毕,所以更新的右边界应该不包含middle,否则将不满足条件,即

    right=middle-1
  2. 左闭右开情况 

    右边界

    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.移除元素

27. 移除元素 - 力扣(LeetCode)

 解题思路

  • 题目要求原地修改,则我们不能重新 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;
}

总结

暴力求解可,双指针更佳。 

今日感受

好久没学算法了,一下子感觉要长脑子了。。。今天学起来感觉思路是流畅的,就是代码写起来很困难,要么是格式不记得,要么是没办法写出心中所想,谁懂这种痛苦!!!不过还好今天也算是重新启航了,坚持下去,多刷!!

 

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值